{
  "openapi": "3.1.0",
  "info": {
    "title": "AllSign API v3",
    "description": "AllSign API v3 — contract-first, camelCase wire, RFC 9457 problem+json errors. See https://developers.allsign.io.",
    "version": "2026-07-11"
  },
  "servers": [
    {
      "url": "/v3",
      "description": "V3 API base path"
    }
  ],
  "paths": {
    "/healthz": {
      "get": {
        "tags": [
          "Health"
        ],
        "summary": "Health check",
        "description": "Sonda de salud pública, sin autenticación. Úsala para verificar que la API v3 está arriba antes de una integración o en tus checks de monitoreo.",
        "operationId": "healthz",
        "responses": {
          "200": {
            "description": "Siempre `{ \"status\": \"ok\" }` cuando el servicio está sano.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthzResponse"
                },
                "example": {
                  "status": "ok"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL",
            "source": "curl \"https://api.allsign.io/v3/healthz\"\n"
          }
        ]
      }
    },
    "/documents": {
      "get": {
        "tags": [
          "Documents"
        ],
        "summary": "List documents",
        "operationId": "listDocuments",
        "security": [
          {
            "Bearer Token": []
          }
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 100,
              "minimum": 1,
              "default": 20,
              "title": "Limit"
            },
            "description": "Resultados por página (1–100, default `20`)."
          },
          {
            "name": "startingAfter",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Startingafter"
            },
            "description": "Cursor: devuelve la página que sigue a este `id` de documento."
          },
          {
            "name": "endingBefore",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Endingbefore"
            },
            "description": "Cursor: devuelve la página anterior a este `id` de documento."
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "$ref": "#/components/schemas/DocumentStatus"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Status"
            },
            "description": "Filtra por estado: `draft`, `collecting_data`, `awaiting_signatures`, `correcting`, `processing`, `completed`, `expired`, `voided`."
          },
          {
            "name": "status[not]",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/DocumentStatus"
                  }
                },
                {
                  "type": "null"
                }
              ],
              "description": "Statuses to hide. Repeat the parameter to hide several, e.g. `?status[not]=voided&status[not]=expired`. Omit to return every status. Documents with no signature state are never hidden. Mutually exclusive with `status`.",
              "title": "Status[Not]"
            },
            "description": "Statuses to hide. Repeat the parameter to hide several, e.g. `?status[not]=voided&status[not]=expired`. Omit to return every status. Documents with no signature state are never hidden. Mutually exclusive with `status`."
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/DocumentSort",
              "default": "-createdAt"
            },
            "description": "Orden. Solo `createdAt` / `updatedAt`, ascendente o descendente con el prefijo `-`. Valores: `createdAt`, `-createdAt`, `updatedAt`, `-updatedAt` (default `-createdAt`). Otro valor es un `422 VALIDATION_ERROR`."
          },
          {
            "name": "scope",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/DocumentScopeEnum",
              "default": "owner"
            },
            "description": "Alcance: `owner` (default), `org`, `tenant`, `accessible`."
          },
          {
            "name": "folderId",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Folderid"
            },
            "description": "Filtra por carpeta (`fld_…`)."
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 255
                },
                {
                  "type": "null"
                }
              ],
              "title": "Search"
            },
            "description": "Búsqueda por texto libre en el nombre (1–255 caracteres)."
          },
          {
            "name": "createdAt[gte]",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "format": "date-time"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Createdat[Gte]"
            },
            "description": "Solo documentos creados en o después de esta fecha (ISO 8601)."
          },
          {
            "name": "createdAt[lte]",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "format": "date-time"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Createdat[Lte]"
            },
            "description": "Solo documentos creados en o antes de esta fecha (ISO 8601)."
          },
          {
            "name": "includeTotal",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean",
              "default": false,
              "title": "Includetotal"
            },
            "description": "Si es `true`, la respuesta incluye `totalCount`. Default `false` (más rápido)."
          },
          {
            "name": "includeFiledDocuments",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean",
              "description": "When false, hides documents the caller has filed into one of their own folders. The auto-created inbox folder does not count as filing. Ignored when `folderId` selects a folder.",
              "default": true,
              "title": "Includefileddocuments"
            },
            "description": "When false, hides documents the caller has filed into one of their own folders. The auto-created inbox folder does not count as filing. Ignored when `folderId` selects a folder."
          }
        ],
        "responses": {
          "200": {
            "description": "Sobre de paginación por cursor (`object: \"list\"`) con objetos Document.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentList"
                },
                "example": {
                  "object": "list",
                  "data": [
                    {
                      "object": "document",
                      "id": "doc_3Nk8sZ2eZvKYlo2C0aBcDeF",
                      "livemode": true,
                      "name": "Contrato de arrendamiento 2026.pdf",
                      "status": "awaiting_signatures",
                      "documentType": "editable",
                      "signerCount": 2,
                      "signedCount": 1,
                      "ownerId": "usr_1a2b3c4d5e6f7g8h",
                      "orgId": "org_9i8u7y6t5r4e3w2q",
                      "folderId": "fld_c0ffeec0ffeec0ff",
                      "expiresAt": "2026-08-01T23:59:59Z",
                      "expirationReminders": [
                        72,
                        24
                      ],
                      "createdAt": "2026-07-11T18:04:00Z",
                      "updatedAt": "2026-07-11T20:15:00Z"
                    }
                  ],
                  "hasMore": true,
                  "limit": 20,
                  "nextCursor": "doc_3Nk8sZ2eZvKYlo2C0aBcDeF",
                  "previousCursor": null,
                  "totalCount": null
                }
              }
            }
          },
          "400": {
            "description": "El identificador en un parámetro está mal formado (`INVALID_ID`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "INVALID_CURSOR": {
                    "summary": "Invalid cursor",
                    "value": {
                      "type": "https://developers.allsign.io/errors#INVALID_CURSOR",
                      "title": "Invalid cursor",
                      "status": 400,
                      "detail": "The pagination cursor is malformed.",
                      "code": "INVALID_CURSOR"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Falta el header `Authorization` o la API key no es válida.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "AUTHENTICATION_REQUIRED": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#AUTHENTICATION_REQUIRED",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "Provide an API key via Authorization: Bearer allsign_live_sk_….",
                      "code": "AUTHENTICATION_REQUIRED"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La API key no tiene el scope requerido para este recurso.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "PERMISSION_DENIED": {
                    "summary": "Permission denied",
                    "value": {
                      "type": "https://developers.allsign.io/errors#PERMISSION_DENIED",
                      "title": "Permission denied",
                      "status": 403,
                      "detail": "This API key is missing the required scope.",
                      "code": "PERMISSION_DENIED",
                      "requiredScope": "document:write",
                      "yourScopes": [
                        "document:read"
                      ]
                    }
                  },
                  "IP_NOT_ALLOWED": {
                    "summary": "IP address not allowed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IP_NOT_ALLOWED",
                      "title": "IP address not allowed",
                      "status": 403,
                      "detail": "Access from this IP is not allowed for this API key.",
                      "code": "IP_NOT_ALLOWED"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "El parámetro no pasa la validación (ej. `period` con un valor fuera del catálogo).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "VALIDATION_ERROR": {
                    "summary": "Validation failed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#VALIDATION_ERROR",
                      "title": "Validation failed",
                      "status": 422,
                      "detail": "One or more fields are invalid.",
                      "code": "VALIDATION_ERROR"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Se superó el límite de tasa de tu API key; reintenta respetando `RateLimit-*` / `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          }
        },
        "description": "Lista tus documentos con paginación por cursor y filtros. El cursor viaja en `startingAfter` (avanzar) o `endingBefore` (retroceder); usa el `id` del último elemento de la página como cursor de la siguiente.",
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL",
            "source": "curl \"https://api.allsign.io/v3/documents?status=awaiting_signatures&limit=20\" \\\n  -H \"Authorization: Bearer allsign_live_sk_...\"\n"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const params = new URLSearchParams({\n  status: 'awaiting_signatures',\n  limit: '20',\n  sort: '-createdAt',\n})\n\nconst res = await fetch(`https://api.allsign.io/v3/documents?${params}`, {\n  headers: { Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}` },\n})\nconst { data, hasMore, nextCursor } = await res.json()\n"
          }
        ]
      },
      "post": {
        "tags": [
          "Documents"
        ],
        "summary": "Create document",
        "description": "Crea un documento a partir de **una plantilla** (`source: \"template\"`) **o** de un **archivo subido en base64** (`source: \"file\"`) — nunca ambos. El campo `source` es un discriminador explícito; si lo omites, se infiere de cuál de `templateId` / `file` mandaste, pero cuando lo incluyes **debe coincidir** con el campo presente. Efectos en entorno `live`: consume 1 o más créditos, arranca un workflow de Temporal y sube el archivo a S3. Con una key `test` el documento es `livemode: false` y no factura.",
        "operationId": "createDocument",
        "security": [
          {
            "Bearer Token": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DocumentCreateRequest"
              },
              "example": {
                "source": "template",
                "templateId": "tmpl_7h6g5f4e3d2c1b0a",
                "templateValues": {
                  "nombre_completo": "Juan Pérez",
                  "monto": "$150,000.00 MXN"
                },
                "signers": [
                  {
                    "email": "juan@ejemplo.com",
                    "name": "Juan Pérez"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Documento creado (mismo shape que Retrieve document).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Document"
                },
                "example": {
                  "object": "document",
                  "id": "doc_5Qr9tA3fZwLZmp3D1bCdEfG",
                  "livemode": true,
                  "name": "contrato.pdf",
                  "status": "draft",
                  "documentType": "editable",
                  "signerCount": 1,
                  "signedCount": 0,
                  "ownerId": "usr_1a2b3c4d5e6f7g8h",
                  "orgId": "org_9i8u7y6t5r4e3w2q",
                  "folderId": null,
                  "expiresAt": null,
                  "expirationReminders": null,
                  "createdAt": "2026-07-12T15:00:00Z",
                  "updatedAt": "2026-07-12T15:00:00Z"
                }
              }
            }
          },
          "400": {
            "description": "El identificador en un parámetro está mal formado (`INVALID_ID`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "INVALID_ID": {
                    "summary": "Malformed identifier",
                    "value": {
                      "type": "https://developers.allsign.io/errors#INVALID_ID",
                      "title": "Malformed identifier",
                      "status": 400,
                      "detail": "Invalid id; expected a typed, prefixed id (e.g. 'doc_…').",
                      "code": "INVALID_ID"
                    }
                  },
                  "IDEMPOTENCY_KEY_REQUIRED": {
                    "summary": "Idempotency key required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IDEMPOTENCY_KEY_REQUIRED",
                      "title": "Idempotency key required",
                      "status": 400,
                      "detail": "POST requests that create or charge require a unique Idempotency-Key (UUID v4).",
                      "code": "IDEMPOTENCY_KEY_REQUIRED"
                    }
                  },
                  "IDEMPOTENCY_KEY_INVALID": {
                    "summary": "Idempotency key invalid",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IDEMPOTENCY_KEY_INVALID",
                      "title": "Idempotency key invalid",
                      "status": 400,
                      "detail": "Idempotency-Key must be a UUID v4.",
                      "code": "IDEMPOTENCY_KEY_INVALID"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Falta el header `Authorization` o la API key no es válida.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "AUTHENTICATION_REQUIRED": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#AUTHENTICATION_REQUIRED",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "Provide an API key via Authorization: Bearer allsign_live_sk_….",
                      "code": "AUTHENTICATION_REQUIRED"
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "Créditos insuficientes en el tenant para crear el documento (`INSUFFICIENT_CREDITS`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "INSUFFICIENT_CREDITS": {
                    "summary": "Insufficient credits",
                    "value": {
                      "type": "https://developers.allsign.io/errors#INSUFFICIENT_CREDITS",
                      "title": "Insufficient credits",
                      "status": 402,
                      "detail": "This tenant does not have enough credits for this operation.",
                      "code": "INSUFFICIENT_CREDITS"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La API key no tiene el scope requerido para este recurso.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "PERMISSION_DENIED": {
                    "summary": "Permission denied",
                    "value": {
                      "type": "https://developers.allsign.io/errors#PERMISSION_DENIED",
                      "title": "Permission denied",
                      "status": 403,
                      "detail": "This API key is missing the required scope.",
                      "code": "PERMISSION_DENIED",
                      "requiredScope": "document:write",
                      "yourScopes": [
                        "document:read"
                      ]
                    }
                  },
                  "IP_NOT_ALLOWED": {
                    "summary": "IP address not allowed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IP_NOT_ALLOWED",
                      "title": "IP address not allowed",
                      "status": 403,
                      "detail": "Access from this IP is not allowed for this API key.",
                      "code": "IP_NOT_ALLOWED"
                    }
                  },
                  "DEV_FEATURE_RESTRICTED": {
                    "summary": "Feature restricted in this environment",
                    "value": {
                      "type": "https://developers.allsign.io/errors#DEV_FEATURE_RESTRICTED",
                      "title": "Feature restricted in this environment",
                      "status": 403,
                      "detail": "This feature is not available for dev/test API keys. Create a live key in your dashboard.",
                      "code": "DEV_FEATURE_RESTRICTED"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "El `templateId` no existe en este entorno (`TEMPLATE_NOT_FOUND`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "TEMPLATE_NOT_FOUND": {
                    "summary": "Template not found",
                    "value": {
                      "type": "https://developers.allsign.io/errors#TEMPLATE_NOT_FOUND",
                      "title": "Template not found",
                      "status": 404,
                      "detail": "No template was found with that id.",
                      "code": "TEMPLATE_NOT_FOUND"
                    }
                  }
                },
                "example": {
                  "type": "about:blank",
                  "title": "Template not found",
                  "status": 404,
                  "code": "TEMPLATE_NOT_FOUND",
                  "detail": "No existe una plantilla con id tmpl_7h6g5f4e3d2c1b0a en este entorno."
                }
              }
            }
          },
          "409": {
            "description": "Reintento con la misma `Idempotency-Key` mientras la petición original sigue en curso.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "IDEMPOTENCY_KEY_REUSED": {
                    "summary": "Idempotency key reused",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IDEMPOTENCY_KEY_REUSED",
                      "title": "Idempotency key reused",
                      "status": 409,
                      "detail": "This Idempotency-Key was already used with a different request.",
                      "code": "IDEMPOTENCY_KEY_REUSED"
                    }
                  },
                  "IDEMPOTENCY_KEY_IN_PROGRESS": {
                    "summary": "Idempotency key in progress",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IDEMPOTENCY_KEY_IN_PROGRESS",
                      "title": "Idempotency key in progress",
                      "status": 409,
                      "detail": "A request with this Idempotency-Key is still in progress.",
                      "code": "IDEMPOTENCY_KEY_IN_PROGRESS",
                      "retryAfter": 2
                    }
                  }
                }
              }
            }
          },
          "413": {
            "description": "El archivo decodificado (`source: \"file\"`) supera 10 MB (`DOCUMENT_TOO_LARGE`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "DOCUMENT_TOO_LARGE": {
                    "summary": "Document too large",
                    "value": {
                      "type": "https://developers.allsign.io/errors#DOCUMENT_TOO_LARGE",
                      "title": "Document too large",
                      "status": 413,
                      "detail": "The decoded file exceeds the 10 MB limit.",
                      "code": "DOCUMENT_TOO_LARGE"
                    }
                  }
                },
                "example": {
                  "type": "about:blank",
                  "title": "Document too large",
                  "status": 413,
                  "code": "DOCUMENT_TOO_LARGE",
                  "detail": "El archivo decodificado supera el límite de 10 MB."
                }
              }
            }
          },
          "422": {
            "description": "El cuerpo no pasa la validación. Con `source: \"template\"`, la causa más común es que falte una variable **requerida** en `templateValues`: cada una viene en `errors[]` con su `field`. No se creó el documento ni se consumió crédito. Puedes anticiparlo con Validate template values.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "VALIDATION_ERROR": {
                    "summary": "Validation failed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#VALIDATION_ERROR",
                      "title": "Validation failed",
                      "status": 422,
                      "detail": "One or more fields are invalid.",
                      "code": "VALIDATION_ERROR"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Se superó el límite de tasa de tu API key; reintenta respetando `RateLimit-*` / `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL (desde plantilla)",
            "source": "curl \"https://api.allsign.io/v3/documents\" \\\n  -H \"Authorization: Bearer allsign_live_sk_...\" \\\n  -H \"Content-Type: application/json\" \\\n  -H \"Idempotency-Key: 9f3c1a2e-8d4b-4c6a-9e21-5b7f0d8a3c14\" \\\n  -d '{\n    \"source\": \"template\",\n    \"templateId\": \"tmpl_7h6g5f4e3d2c1b0a\",\n    \"templateValues\": {\n      \"nombre_completo\": \"Juan Pérez\",\n      \"monto\": \"$150,000.00 MXN\"\n    },\n    \"signers\": [\n      { \"email\": \"juan@ejemplo.com\", \"name\": \"Juan Pérez\" }\n    ]\n  }'\n"
          },
          {
            "lang": "typescript",
            "label": "TypeScript (desde plantilla)",
            "source": "const res = await fetch('https://api.allsign.io/v3/documents', {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}`,\n    'Content-Type': 'application/json',\n    'Idempotency-Key': '9f3c1a2e-8d4b-4c6a-9e21-5b7f0d8a3c14',\n  },\n  body: JSON.stringify({\n    source: 'template',\n    templateId: 'tmpl_7h6g5f4e3d2c1b0a',\n    templateValues: {\n      nombre_completo: 'Juan Pérez',\n      monto: '$150,000.00 MXN',\n    },\n    signers: [{ email: 'juan@ejemplo.com', name: 'Juan Pérez' }],\n  }),\n})\nconst document = await res.json()\n"
          },
          {
            "lang": "python",
            "label": "Python (desde plantilla)",
            "source": "import requests\n\nres = requests.post(\n    'https://api.allsign.io/v3/documents',\n    headers={\n        'Authorization': 'Bearer allsign_live_sk_...',\n        'Idempotency-Key': '9f3c1a2e-8d4b-4c6a-9e21-5b7f0d8a3c14',\n    },\n    json={\n        'source': 'template',\n        'templateId': 'tmpl_7h6g5f4e3d2c1b0a',\n        'templateValues': {\n            'nombre_completo': 'Juan Pérez',\n            'monto': '$150,000.00 MXN',\n        },\n        'signers': [{'email': 'juan@ejemplo.com', 'name': 'Juan Pérez'}],\n    },\n)\ndocument = res.json()\n"
          },
          {
            "lang": "shell",
            "label": "cURL (desde archivo)",
            "source": "curl \"https://api.allsign.io/v3/documents\" \\\n  -H \"Authorization: Bearer allsign_live_sk_...\" \\\n  -H \"Content-Type: application/json\" \\\n  -H \"Idempotency-Key: 9f3c1a2e-8d4b-4c6a-9e21-5b7f0d8a3c14\" \\\n  -d '{\n    \"source\": \"file\",\n    \"file\": {\n      \"content\": \"JVBERi0xLjQKJc...\",\n      \"fileType\": \"pdf\",\n      \"name\": \"contrato.pdf\"\n    },\n    \"signers\": [\n      { \"email\": \"juan@ejemplo.com\", \"name\": \"Juan Pérez\" }\n    ]\n  }'\n"
          },
          {
            "lang": "typescript",
            "label": "TypeScript (desde archivo)",
            "source": "import { readFileSync } from 'node:fs'\n\nconst content = readFileSync('contrato.pdf').toString('base64')\n\nconst res = await fetch('https://api.allsign.io/v3/documents', {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}`,\n    'Content-Type': 'application/json',\n    'Idempotency-Key': '9f3c1a2e-8d4b-4c6a-9e21-5b7f0d8a3c14',\n  },\n  body: JSON.stringify({\n    source: 'file',\n    file: { content, fileType: 'pdf', name: 'contrato.pdf' },\n    signers: [{ email: 'juan@ejemplo.com', name: 'Juan Pérez' }],\n  }),\n})\nconst document = await res.json()\n"
          }
        ]
      }
    },
    "/documents/stats": {
      "get": {
        "tags": [
          "Documents"
        ],
        "summary": "Get aggregate statistics",
        "description": "Conteos agregados en el mismo `scope` que `GET /documents`. Sin rango de fechas, usa los últimos 365 días por default; `recentCount` siempre son los últimos 7 días **dentro** de esa ventana, no de todo el histórico. No es un objeto recurso (sin `livemode`) — es un resumen, como `List documents` pero contado en vez de listado.",
        "operationId": "getDocumentStats",
        "security": [
          {
            "Bearer Token": []
          }
        ],
        "parameters": [
          {
            "name": "scope",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/DocumentScopeEnum",
              "default": "owner"
            },
            "description": "Alcance: `owner` (default), `org`, `tenant`, `accessible`."
          },
          {
            "name": "createdAt[gte]",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "format": "date-time"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Createdat[Gte]"
            },
            "description": "Solo cuenta documentos creados en o después de esta fecha (ISO 8601)."
          },
          {
            "name": "createdAt[lte]",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "format": "date-time"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Createdat[Lte]"
            },
            "description": "Solo cuenta documentos creados en o antes de esta fecha (ISO 8601)."
          }
        ],
        "responses": {
          "200": {
            "description": "Los 5 conteos agregados.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentStats"
                },
                "example": {
                  "totalDocuments": 128,
                  "totalCompleted": 94,
                  "totalPending": 22,
                  "totalConfiguring": 12,
                  "recentCount": 7
                }
              }
            }
          },
          "401": {
            "description": "Falta el header `Authorization` o la API key no es válida.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "AUTHENTICATION_REQUIRED": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#AUTHENTICATION_REQUIRED",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "Provide an API key via Authorization: Bearer allsign_live_sk_….",
                      "code": "AUTHENTICATION_REQUIRED"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La API key no tiene el scope requerido para este recurso.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "PERMISSION_DENIED": {
                    "summary": "Permission denied",
                    "value": {
                      "type": "https://developers.allsign.io/errors#PERMISSION_DENIED",
                      "title": "Permission denied",
                      "status": 403,
                      "detail": "This API key is missing the required scope.",
                      "code": "PERMISSION_DENIED",
                      "requiredScope": "document:write",
                      "yourScopes": [
                        "document:read"
                      ]
                    }
                  },
                  "IP_NOT_ALLOWED": {
                    "summary": "IP address not allowed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IP_NOT_ALLOWED",
                      "title": "IP address not allowed",
                      "status": 403,
                      "detail": "Access from this IP is not allowed for this API key.",
                      "code": "IP_NOT_ALLOWED"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "El parámetro no pasa la validación (ej. `period` con un valor fuera del catálogo).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "VALIDATION_ERROR": {
                    "summary": "Validation failed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#VALIDATION_ERROR",
                      "title": "Validation failed",
                      "status": 422,
                      "detail": "One or more fields are invalid.",
                      "code": "VALIDATION_ERROR"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Se superó el límite de tasa de tu API key; reintenta respetando `RateLimit-*` / `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL",
            "source": "curl \"https://api.allsign.io/v3/documents/stats?scope=tenant\" \\\n  -H \"Authorization: Bearer allsign_live_sk_...\"\n"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const res = await fetch('https://api.allsign.io/v3/documents/stats?scope=tenant', {\n  headers: { Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}` },\n})\nconst stats = await res.json()\n"
          }
        ]
      }
    },
    "/documents/{document_id}": {
      "get": {
        "tags": [
          "Documents"
        ],
        "summary": "Retrieve document",
        "operationId": "getDocument",
        "security": [
          {
            "Bearer Token": []
          }
        ],
        "parameters": [
          {
            "name": "document_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Document Id"
            },
            "description": "ID del documento (`doc_…`)."
          },
          {
            "name": "expand",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Expand"
            },
            "description": "Lista separada por comas de sub-recursos a expandir en línea. Si se omite, la respuesta trae solo los campos del propio documento."
          }
        ],
        "responses": {
          "200": {
            "description": "El objeto Document.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Document"
                },
                "example": {
                  "object": "document",
                  "id": "doc_5Qr9tA3fZwLZmp3D1bCdEfG",
                  "livemode": true,
                  "name": "Contrato de arrendamiento 2026.pdf",
                  "status": "awaiting_signatures",
                  "documentType": "editable",
                  "signerCount": 2,
                  "signedCount": 1,
                  "ownerId": "usr_1a2b3c4d5e6f7g8h",
                  "orgId": "org_9i8u7y6t5r4e3w2q",
                  "folderId": "fld_c0ffeec0ffeec0ff",
                  "expiresAt": "2026-08-01T23:59:59Z",
                  "expirationReminders": [
                    72,
                    24
                  ],
                  "createdAt": "2026-07-11T18:04:00Z",
                  "updatedAt": "2026-07-11T20:15:00Z"
                }
              }
            }
          },
          "400": {
            "description": "El identificador en un parámetro está mal formado (`INVALID_ID`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "INVALID_ID": {
                    "summary": "Malformed identifier",
                    "value": {
                      "type": "https://developers.allsign.io/errors#INVALID_ID",
                      "title": "Malformed identifier",
                      "status": 400,
                      "detail": "Invalid id; expected a typed, prefixed id (e.g. 'doc_…').",
                      "code": "INVALID_ID"
                    }
                  },
                  "EXPAND_DEPTH_EXCEEDED": {
                    "summary": "Expand depth exceeded",
                    "value": {
                      "type": "https://developers.allsign.io/errors#EXPAND_DEPTH_EXCEEDED",
                      "title": "Expand depth exceeded",
                      "status": 400,
                      "detail": "At most 3 expand paths are allowed.",
                      "code": "EXPAND_DEPTH_EXCEEDED"
                    }
                  },
                  "INVALID_EXPAND": {
                    "summary": "Invalid expand path",
                    "value": {
                      "type": "https://developers.allsign.io/errors#INVALID_EXPAND",
                      "title": "Invalid expand path",
                      "status": 400,
                      "detail": "Unknown expand path.",
                      "code": "INVALID_EXPAND"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Falta el header `Authorization` o la API key no es válida.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "AUTHENTICATION_REQUIRED": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#AUTHENTICATION_REQUIRED",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "Provide an API key via Authorization: Bearer allsign_live_sk_….",
                      "code": "AUTHENTICATION_REQUIRED"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La API key no tiene el scope requerido para este recurso.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "PERMISSION_DENIED": {
                    "summary": "Permission denied",
                    "value": {
                      "type": "https://developers.allsign.io/errors#PERMISSION_DENIED",
                      "title": "Permission denied",
                      "status": 403,
                      "detail": "This API key is missing the required scope.",
                      "code": "PERMISSION_DENIED",
                      "requiredScope": "document:write",
                      "yourScopes": [
                        "document:read"
                      ]
                    }
                  },
                  "IP_NOT_ALLOWED": {
                    "summary": "IP address not allowed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IP_NOT_ALLOWED",
                      "title": "IP address not allowed",
                      "status": 403,
                      "detail": "Access from this IP is not allowed for this API key.",
                      "code": "IP_NOT_ALLOWED"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No existe un documento con ese `id` en este entorno (`DOCUMENT_NOT_FOUND`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "DOCUMENT_NOT_FOUND": {
                    "summary": "Document not found",
                    "value": {
                      "type": "https://developers.allsign.io/errors#DOCUMENT_NOT_FOUND",
                      "title": "Document not found",
                      "status": 404,
                      "detail": "No document was found with that id.",
                      "code": "DOCUMENT_NOT_FOUND"
                    }
                  }
                },
                "example": {
                  "type": "about:blank",
                  "title": "Document not found",
                  "status": 404,
                  "code": "DOCUMENT_NOT_FOUND",
                  "detail": "No existe un documento con ese id en este entorno."
                }
              }
            }
          },
          "422": {
            "description": "El parámetro no pasa la validación (ej. `period` con un valor fuera del catálogo).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Se superó el límite de tasa de tu API key; reintenta respetando `RateLimit-*` / `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          }
        },
        "description": "Consulta un documento por su `id`.",
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL",
            "source": "curl \"https://api.allsign.io/v3/documents/doc_5Qr9tA3fZwLZmp3D1bCdEfG\" \\\n  -H \"Authorization: Bearer allsign_live_sk_...\"\n"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const id = 'doc_5Qr9tA3fZwLZmp3D1bCdEfG'\nconst res = await fetch(`https://api.allsign.io/v3/documents/${id}`, {\n  headers: { Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}` },\n})\nconst document = await res.json()\n"
          }
        ]
      },
      "patch": {
        "tags": [
          "Documents"
        ],
        "summary": "Update document",
        "description": "Merge-patch parcial: solo se modifican los campos que envías. Los únicos campos mutables son `name` y `folderId`. Enviar cualquier otro campo (`status`, `ownerId`, `id`, `createdAt`, …) se rechaza al parsear con **422 `VALIDATION_ERROR`** nombrando el campo ofensor — así se protege un campo inmutable.",
        "operationId": "updateDocument",
        "security": [
          {
            "Bearer Token": []
          }
        ],
        "parameters": [
          {
            "name": "document_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Document Id"
            },
            "description": "ID del documento (`doc_…`)."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DocumentUpdateRequest"
              },
              "example": {
                "name": "Contrato final v2.pdf",
                "folderId": "fld_c0ffeec0ffeec0ff"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "El objeto Document actualizado.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Document"
                },
                "example": {
                  "object": "document",
                  "id": "doc_5Qr9tA3fZwLZmp3D1bCdEfG",
                  "livemode": true,
                  "name": "Contrato final v2.pdf",
                  "status": "awaiting_signatures",
                  "documentType": "editable",
                  "signerCount": 2,
                  "signedCount": 1,
                  "ownerId": "usr_1a2b3c4d5e6f7g8h",
                  "orgId": "org_9i8u7y6t5r4e3w2q",
                  "folderId": "fld_c0ffeec0ffeec0ff",
                  "expiresAt": "2026-08-01T23:59:59Z",
                  "expirationReminders": [
                    72,
                    24
                  ],
                  "createdAt": "2026-07-11T18:04:00Z",
                  "updatedAt": "2026-07-12T16:20:00Z"
                }
              }
            }
          },
          "400": {
            "description": "El identificador en un parámetro está mal formado (`INVALID_ID`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "INVALID_ID": {
                    "summary": "Malformed identifier",
                    "value": {
                      "type": "https://developers.allsign.io/errors#INVALID_ID",
                      "title": "Malformed identifier",
                      "status": 400,
                      "detail": "Invalid id; expected a typed, prefixed id (e.g. 'doc_…').",
                      "code": "INVALID_ID"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Falta el header `Authorization` o la API key no es válida.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "AUTHENTICATION_REQUIRED": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#AUTHENTICATION_REQUIRED",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "Provide an API key via Authorization: Bearer allsign_live_sk_….",
                      "code": "AUTHENTICATION_REQUIRED"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La API key no tiene el scope requerido para este recurso.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "PERMISSION_DENIED": {
                    "summary": "Permission denied",
                    "value": {
                      "type": "https://developers.allsign.io/errors#PERMISSION_DENIED",
                      "title": "Permission denied",
                      "status": 403,
                      "detail": "This API key is missing the required scope.",
                      "code": "PERMISSION_DENIED",
                      "requiredScope": "document:write",
                      "yourScopes": [
                        "document:read"
                      ]
                    }
                  },
                  "IP_NOT_ALLOWED": {
                    "summary": "IP address not allowed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IP_NOT_ALLOWED",
                      "title": "IP address not allowed",
                      "status": 403,
                      "detail": "Access from this IP is not allowed for this API key.",
                      "code": "IP_NOT_ALLOWED"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No existe un documento con ese `id` en este entorno (`DOCUMENT_NOT_FOUND`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "DOCUMENT_NOT_FOUND": {
                    "summary": "Document not found",
                    "value": {
                      "type": "https://developers.allsign.io/errors#DOCUMENT_NOT_FOUND",
                      "title": "Document not found",
                      "status": 404,
                      "detail": "No document was found with that id.",
                      "code": "DOCUMENT_NOT_FOUND"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Campo inmutable o desconocido en el body (`VALIDATION_ERROR`), o valor inválido.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "VALIDATION_ERROR": {
                    "summary": "Validation failed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#VALIDATION_ERROR",
                      "title": "Validation failed",
                      "status": 422,
                      "detail": "One or more fields are invalid.",
                      "code": "VALIDATION_ERROR"
                    }
                  }
                },
                "example": {
                  "type": "about:blank",
                  "title": "Validation error",
                  "status": 422,
                  "code": "VALIDATION_ERROR",
                  "detail": "El campo 'status' no se puede modificar con PATCH."
                }
              }
            }
          },
          "429": {
            "description": "Se superó el límite de tasa de tu API key; reintenta respetando `RateLimit-*` / `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL",
            "source": "curl -X PATCH \"https://api.allsign.io/v3/documents/doc_5Qr9tA3fZwLZmp3D1bCdEfG\" \\\n  -H \"Authorization: Bearer allsign_live_sk_...\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{ \"name\": \"Contrato final v2.pdf\", \"folderId\": \"fld_c0ffeec0ffeec0ff\" }'\n"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const id = 'doc_5Qr9tA3fZwLZmp3D1bCdEfG'\nconst res = await fetch(`https://api.allsign.io/v3/documents/${id}`, {\n  method: 'PATCH',\n  headers: {\n    Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    name: 'Contrato final v2.pdf',\n    folderId: 'fld_c0ffeec0ffeec0ff',\n  }),\n})\nconst document = await res.json()\n"
          }
        ]
      }
    },
    "/documents/bulk-sends": {
      "post": {
        "tags": [
          "Documents"
        ],
        "summary": "Create bulk send",
        "description": "Sube un PDF una sola vez y crea N documentos independientes, uno por destinatario, cada uno con su propio enlace de firma. **Asíncrono**: valida todo de forma síncrona (créditos, tamaño de archivo, forma del body) y agenda el trabajo pesado — la respuesta es un **202** con el lote en `processing` y cada `items[].status` en `pending`. Haz *poll* de `GET /documents/bulk-sends/{id}` (Get bulk send) hasta que `status` cambie a `completed` o `partialError`. `Idempotency-Key` es **obligatorio**: un reintento con la misma key devuelve el MISMO 202 + el mismo id de lote (`Idempotency-Replayed: true`) en vez de agendar el trabajo dos veces — nunca cobra créditos ni invita dos veces por un retry.",
        "operationId": "createBulkSend",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BulkSendRequest"
              },
              "example": {
                "name": "Política de privacidad 2026",
                "file": {
                  "content": "JVBERi0xLjQKJcOkw7zDtsO...",
                  "fileType": "pdf"
                },
                "recipients": [
                  {
                    "email": "ana@ejemplo.com",
                    "name": "Ana Torres"
                  },
                  {
                    "email": "luis@ejemplo.com",
                    "name": "Luis Gómez"
                  }
                ],
                "sendInvites": true
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "description": "El lote agendado — header `Location` apunta a Get bulk send; `status: \"processing\"`, cada item `pending`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkSendResponse"
                },
                "example": {
                  "id": "bat_7NqW4rZpXyBt2eLmQaVh8f",
                  "livemode": true,
                  "status": "processing",
                  "totalCount": 2,
                  "successCount": 0,
                  "errorCount": 0,
                  "items": [
                    {
                      "recipientEmail": "ana@ejemplo.com",
                      "documentId": null,
                      "status": "pending",
                      "error": null
                    },
                    {
                      "recipientEmail": "luis@ejemplo.com",
                      "documentId": null,
                      "status": "pending",
                      "error": null
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "El identificador en un parámetro está mal formado (`INVALID_ID`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "INVALID_ID": {
                    "summary": "Malformed identifier",
                    "value": {
                      "type": "https://developers.allsign.io/errors#INVALID_ID",
                      "title": "Malformed identifier",
                      "status": 400,
                      "detail": "Invalid id; expected a typed, prefixed id (e.g. 'doc_…').",
                      "code": "INVALID_ID"
                    }
                  },
                  "IDEMPOTENCY_KEY_REQUIRED": {
                    "summary": "Idempotency key required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IDEMPOTENCY_KEY_REQUIRED",
                      "title": "Idempotency key required",
                      "status": 400,
                      "detail": "POST requests that create or charge require a unique Idempotency-Key (UUID v4).",
                      "code": "IDEMPOTENCY_KEY_REQUIRED"
                    }
                  },
                  "IDEMPOTENCY_KEY_INVALID": {
                    "summary": "Idempotency key invalid",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IDEMPOTENCY_KEY_INVALID",
                      "title": "Idempotency key invalid",
                      "status": 400,
                      "detail": "Idempotency-Key must be a UUID v4.",
                      "code": "IDEMPOTENCY_KEY_INVALID"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Falta el header `Authorization` o la API key no es válida.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "AUTHENTICATION_REQUIRED": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#AUTHENTICATION_REQUIRED",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "Provide an API key via Authorization: Bearer allsign_live_sk_….",
                      "code": "AUTHENTICATION_REQUIRED"
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "Créditos insuficientes en el tenant para los N documentos (`INSUFFICIENT_CREDITS`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "INSUFFICIENT_CREDITS": {
                    "summary": "Insufficient credits",
                    "value": {
                      "type": "https://developers.allsign.io/errors#INSUFFICIENT_CREDITS",
                      "title": "Insufficient credits",
                      "status": 402,
                      "detail": "This tenant does not have enough credits for this operation.",
                      "code": "INSUFFICIENT_CREDITS"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La API key no tiene el scope requerido para este recurso.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "PERMISSION_DENIED": {
                    "summary": "Permission denied",
                    "value": {
                      "type": "https://developers.allsign.io/errors#PERMISSION_DENIED",
                      "title": "Permission denied",
                      "status": 403,
                      "detail": "This API key is missing the required scope.",
                      "code": "PERMISSION_DENIED",
                      "requiredScope": "document:write",
                      "yourScopes": [
                        "document:read"
                      ]
                    }
                  },
                  "IP_NOT_ALLOWED": {
                    "summary": "IP address not allowed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IP_NOT_ALLOWED",
                      "title": "IP address not allowed",
                      "status": 403,
                      "detail": "Access from this IP is not allowed for this API key.",
                      "code": "IP_NOT_ALLOWED"
                    }
                  },
                  "DEV_FEATURE_RESTRICTED": {
                    "summary": "Feature restricted in this environment",
                    "value": {
                      "type": "https://developers.allsign.io/errors#DEV_FEATURE_RESTRICTED",
                      "title": "Feature restricted in this environment",
                      "status": 403,
                      "detail": "This feature is not available for dev/test API keys. Create a live key in your dashboard.",
                      "code": "DEV_FEATURE_RESTRICTED"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Reintento con la misma `Idempotency-Key` pero un body distinto (`IDEMPOTENCY_KEY_REUSED`), o la petición original sigue en curso (`IDEMPOTENCY_KEY_IN_PROGRESS`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "IDEMPOTENCY_KEY_REUSED": {
                    "summary": "Idempotency key reused",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IDEMPOTENCY_KEY_REUSED",
                      "title": "Idempotency key reused",
                      "status": 409,
                      "detail": "This Idempotency-Key was already used with a different request.",
                      "code": "IDEMPOTENCY_KEY_REUSED"
                    }
                  },
                  "IDEMPOTENCY_KEY_IN_PROGRESS": {
                    "summary": "Idempotency key in progress",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IDEMPOTENCY_KEY_IN_PROGRESS",
                      "title": "Idempotency key in progress",
                      "status": 409,
                      "detail": "A request with this Idempotency-Key is still in progress.",
                      "code": "IDEMPOTENCY_KEY_IN_PROGRESS",
                      "retryAfter": 2
                    }
                  }
                }
              }
            }
          },
          "413": {
            "description": "El PDF decodificado supera 10 MB (`DOCUMENT_TOO_LARGE`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "DOCUMENT_TOO_LARGE": {
                    "summary": "Document too large",
                    "value": {
                      "type": "https://developers.allsign.io/errors#DOCUMENT_TOO_LARGE",
                      "title": "Document too large",
                      "status": 413,
                      "detail": "The decoded file exceeds the 10 MB limit.",
                      "code": "DOCUMENT_TOO_LARGE"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "El parámetro no pasa la validación (ej. `period` con un valor fuera del catálogo).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "VALIDATION_ERROR": {
                    "summary": "Validation failed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#VALIDATION_ERROR",
                      "title": "Validation failed",
                      "status": 422,
                      "detail": "One or more fields are invalid.",
                      "code": "VALIDATION_ERROR"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Se superó el límite de tasa de tu API key; reintenta respetando `RateLimit-*` / `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer Token": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL",
            "source": "curl -X POST \"https://api.allsign.io/v3/documents/bulk-sends\" \\\n  -H \"Authorization: Bearer allsign_live_sk_...\" \\\n  -H \"Content-Type: application/json\" \\\n  -H \"Idempotency-Key: $(uuidgen)\" \\\n  -d '{\n    \"name\": \"Política de privacidad 2026\",\n    \"file\": { \"content\": \"JVBERi0...\", \"fileType\": \"pdf\" },\n    \"recipients\": [\n      { \"email\": \"ana@ejemplo.com\", \"name\": \"Ana Torres\" },\n      { \"email\": \"luis@ejemplo.com\", \"name\": \"Luis Gómez\" }\n    ]\n  }'\n"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const res = await fetch('https://api.allsign.io/v3/documents/bulk-sends', {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}`,\n    'Content-Type': 'application/json',\n    'Idempotency-Key': crypto.randomUUID(),\n  },\n  body: JSON.stringify({\n    name: 'Política de privacidad 2026',\n    file: { content: pdfBase64, fileType: 'pdf' },\n    recipients: [\n      { email: 'ana@ejemplo.com', name: 'Ana Torres' },\n      { email: 'luis@ejemplo.com', name: 'Luis Gómez' },\n    ],\n  }),\n})\nconst batch = await res.json()\nconst batchId = res.headers.get('Location')?.split('/').pop() ?? batch.id\n"
          }
        ]
      }
    },
    "/documents/bulk-sends/{batch_id}": {
      "get": {
        "tags": [
          "Documents"
        ],
        "summary": "Get bulk send",
        "description": "Consulta el resultado de un `createBulkSend` asíncrono. Usa el MISMO objeto que la respuesta 202 original — `status` empieza en `processing` (todos los items `pending`) y se asienta en `completed` o `partialError` una vez que cada destinatario fue intentado.",
        "operationId": "getBulkSend",
        "security": [
          {
            "Bearer Token": []
          }
        ],
        "parameters": [
          {
            "name": "batch_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Batch Id"
            },
            "description": "ID del lote (`bat_…`), del header `Location` de Create bulk send."
          }
        ],
        "responses": {
          "200": {
            "description": "El lote — `status`/`items[]` reflejan el progreso más reciente.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkSendResponse"
                },
                "example": {
                  "id": "bat_7NqW4rZpXyBt2eLmQaVh8f",
                  "livemode": true,
                  "status": "completed",
                  "totalCount": 2,
                  "successCount": 2,
                  "errorCount": 0,
                  "items": [
                    {
                      "recipientEmail": "ana@ejemplo.com",
                      "documentId": "doc_3Nk8sZ2eZvKYlo2C0aBcDeF",
                      "status": "sent",
                      "error": null
                    },
                    {
                      "recipientEmail": "luis@ejemplo.com",
                      "documentId": "doc_5Qr9tA3fZwLZmp3D1bCdEfG",
                      "status": "sent",
                      "error": null
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "El identificador en un parámetro está mal formado (`INVALID_ID`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "INVALID_ID": {
                    "summary": "Malformed identifier",
                    "value": {
                      "type": "https://developers.allsign.io/errors#INVALID_ID",
                      "title": "Malformed identifier",
                      "status": 400,
                      "detail": "Invalid id; expected a typed, prefixed id (e.g. 'doc_…').",
                      "code": "INVALID_ID"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Falta el header `Authorization` o la API key no es válida.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "AUTHENTICATION_REQUIRED": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#AUTHENTICATION_REQUIRED",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "Provide an API key via Authorization: Bearer allsign_live_sk_….",
                      "code": "AUTHENTICATION_REQUIRED"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La API key no tiene el scope requerido para este recurso.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "PERMISSION_DENIED": {
                    "summary": "Permission denied",
                    "value": {
                      "type": "https://developers.allsign.io/errors#PERMISSION_DENIED",
                      "title": "Permission denied",
                      "status": 403,
                      "detail": "This API key is missing the required scope.",
                      "code": "PERMISSION_DENIED",
                      "requiredScope": "document:write",
                      "yourScopes": [
                        "document:read"
                      ]
                    }
                  },
                  "IP_NOT_ALLOWED": {
                    "summary": "IP address not allowed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IP_NOT_ALLOWED",
                      "title": "IP address not allowed",
                      "status": 403,
                      "detail": "Access from this IP is not allowed for this API key.",
                      "code": "IP_NOT_ALLOWED"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No existe un lote con ese `id` en este entorno (`BATCH_NOT_FOUND`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "BATCH_NOT_FOUND": {
                    "summary": "Bulk-send batch not found",
                    "value": {
                      "type": "https://developers.allsign.io/errors#BATCH_NOT_FOUND",
                      "title": "Bulk-send batch not found",
                      "status": 404,
                      "detail": "No bulk-send batch was found with that id.",
                      "code": "BATCH_NOT_FOUND"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Se superó el límite de tasa de tu API key; reintenta respetando `RateLimit-*` / `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL",
            "source": "curl \"https://api.allsign.io/v3/documents/bulk-sends/bat_7NqW4rZpXyBt2eLmQaVh8f\" \\\n  -H \"Authorization: Bearer allsign_live_sk_...\"\n"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "async function pollBulkSend(id) {\n  while (true) {\n    const res = await fetch(`https://api.allsign.io/v3/documents/bulk-sends/${id}`, {\n      headers: { Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}` },\n    })\n    const batch = await res.json()\n    if (batch.status !== 'processing') return batch\n    await new Promise((r) => setTimeout(r, 2000))\n  }\n}\n"
          }
        ]
      }
    },
    "/documents/{document_id}/send": {
      "post": {
        "tags": [
          "Documents"
        ],
        "summary": "Send document",
        "description": "Cobra los créditos, avanza el estado del documento y despacha las invitaciones de firma (email o WhatsApp vía Temporal). Si omites `recipients`, se invita a los firmantes ya adjuntos al documento; si los incluyes, defines a quién invitar. La idempotencia llega en una fase posterior, así que un reintento ingenuo hoy puede volver a invitar.",
        "operationId": "sendDocument",
        "security": [
          {
            "Bearer Token": []
          }
        ],
        "parameters": [
          {
            "name": "document_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Document Id"
            },
            "description": "ID del documento (`doc_…`)."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendRequest"
              },
              "example": {
                "recipients": [
                  {
                    "email": "juan@ejemplo.com",
                    "name": "Juan Pérez"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "El Document; su `status` avanza (típicamente a `awaiting_signatures`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Document"
                },
                "example": {
                  "object": "document",
                  "id": "doc_5Qr9tA3fZwLZmp3D1bCdEfG",
                  "livemode": true,
                  "name": "Contrato de arrendamiento 2026.pdf",
                  "status": "awaiting_signatures",
                  "documentType": "editable",
                  "signerCount": 1,
                  "signedCount": 0,
                  "ownerId": "usr_1a2b3c4d5e6f7g8h",
                  "orgId": "org_9i8u7y6t5r4e3w2q",
                  "folderId": null,
                  "expiresAt": null,
                  "expirationReminders": null,
                  "createdAt": "2026-07-12T15:00:00Z",
                  "updatedAt": "2026-07-12T15:05:00Z"
                }
              }
            }
          },
          "400": {
            "description": "El identificador en un parámetro está mal formado (`INVALID_ID`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "INVALID_ID": {
                    "summary": "Malformed identifier",
                    "value": {
                      "type": "https://developers.allsign.io/errors#INVALID_ID",
                      "title": "Malformed identifier",
                      "status": 400,
                      "detail": "Invalid id; expected a typed, prefixed id (e.g. 'doc_…').",
                      "code": "INVALID_ID"
                    }
                  },
                  "IDEMPOTENCY_KEY_REQUIRED": {
                    "summary": "Idempotency key required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IDEMPOTENCY_KEY_REQUIRED",
                      "title": "Idempotency key required",
                      "status": 400,
                      "detail": "POST requests that create or charge require a unique Idempotency-Key (UUID v4).",
                      "code": "IDEMPOTENCY_KEY_REQUIRED"
                    }
                  },
                  "IDEMPOTENCY_KEY_INVALID": {
                    "summary": "Idempotency key invalid",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IDEMPOTENCY_KEY_INVALID",
                      "title": "Idempotency key invalid",
                      "status": 400,
                      "detail": "Idempotency-Key must be a UUID v4.",
                      "code": "IDEMPOTENCY_KEY_INVALID"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Falta el header `Authorization` o la API key no es válida.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "AUTHENTICATION_REQUIRED": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#AUTHENTICATION_REQUIRED",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "Provide an API key via Authorization: Bearer allsign_live_sk_….",
                      "code": "AUTHENTICATION_REQUIRED"
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "Créditos insuficientes en el tenant para despachar el envío (`INSUFFICIENT_CREDITS`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "INSUFFICIENT_CREDITS": {
                    "summary": "Insufficient credits",
                    "value": {
                      "type": "https://developers.allsign.io/errors#INSUFFICIENT_CREDITS",
                      "title": "Insufficient credits",
                      "status": 402,
                      "detail": "This tenant does not have enough credits for this operation.",
                      "code": "INSUFFICIENT_CREDITS"
                    }
                  }
                },
                "example": {
                  "type": "about:blank",
                  "title": "Insufficient credits",
                  "status": 402,
                  "code": "INSUFFICIENT_CREDITS",
                  "detail": "Tu tenant no tiene créditos suficientes para enviar este documento."
                }
              }
            }
          },
          "403": {
            "description": "La API key no tiene el scope requerido para este recurso.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "PERMISSION_DENIED": {
                    "summary": "Permission denied",
                    "value": {
                      "type": "https://developers.allsign.io/errors#PERMISSION_DENIED",
                      "title": "Permission denied",
                      "status": 403,
                      "detail": "This API key is missing the required scope.",
                      "code": "PERMISSION_DENIED",
                      "requiredScope": "document:write",
                      "yourScopes": [
                        "document:read"
                      ]
                    }
                  },
                  "IP_NOT_ALLOWED": {
                    "summary": "IP address not allowed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IP_NOT_ALLOWED",
                      "title": "IP address not allowed",
                      "status": 403,
                      "detail": "Access from this IP is not allowed for this API key.",
                      "code": "IP_NOT_ALLOWED"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No existe un documento con ese `id` en este entorno (`DOCUMENT_NOT_FOUND`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "DOCUMENT_NOT_FOUND": {
                    "summary": "Document not found",
                    "value": {
                      "type": "https://developers.allsign.io/errors#DOCUMENT_NOT_FOUND",
                      "title": "Document not found",
                      "status": 404,
                      "detail": "No document was found with that id.",
                      "code": "DOCUMENT_NOT_FOUND"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "El documento no está en un estado válido para enviarse.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "DOCUMENT_ALREADY_SIGNED": {
                    "summary": "Document already signed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#DOCUMENT_ALREADY_SIGNED",
                      "title": "Document already signed",
                      "status": 409,
                      "detail": "The document is already fully signed.",
                      "code": "DOCUMENT_ALREADY_SIGNED"
                    }
                  },
                  "DOCUMENT_NOT_SENDABLE": {
                    "summary": "Document not sendable",
                    "value": {
                      "type": "https://developers.allsign.io/errors#DOCUMENT_NOT_SENDABLE",
                      "title": "Document not sendable",
                      "status": 409,
                      "detail": "The document has no signature fields, or an owner variable is still pending.",
                      "code": "DOCUMENT_NOT_SENDABLE"
                    }
                  },
                  "IDEMPOTENCY_KEY_REUSED": {
                    "summary": "Idempotency key reused",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IDEMPOTENCY_KEY_REUSED",
                      "title": "Idempotency key reused",
                      "status": 409,
                      "detail": "This Idempotency-Key was already used with a different request.",
                      "code": "IDEMPOTENCY_KEY_REUSED"
                    }
                  },
                  "IDEMPOTENCY_KEY_IN_PROGRESS": {
                    "summary": "Idempotency key in progress",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IDEMPOTENCY_KEY_IN_PROGRESS",
                      "title": "Idempotency key in progress",
                      "status": 409,
                      "detail": "A request with this Idempotency-Key is still in progress.",
                      "code": "IDEMPOTENCY_KEY_IN_PROGRESS",
                      "retryAfter": 2
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "El parámetro no pasa la validación (ej. `period` con un valor fuera del catálogo).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "VALIDATION_ERROR": {
                    "summary": "Validation failed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#VALIDATION_ERROR",
                      "title": "Validation failed",
                      "status": 422,
                      "detail": "One or more fields are invalid.",
                      "code": "VALIDATION_ERROR"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Se superó el límite de tasa de tu API key; reintenta respetando `RateLimit-*` / `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL",
            "source": "curl \"https://api.allsign.io/v3/documents/doc_5Qr9tA3fZwLZmp3D1bCdEfG/send\" \\\n  -H \"Authorization: Bearer allsign_live_sk_...\" \\\n  -H \"Content-Type: application/json\" \\\n  -H \"Idempotency-Key: 7d1f4c8a-2e6b-4a3d-b590-8c2f7e1a6d43\" \\\n  -d '{\n    \"recipients\": [\n      { \"email\": \"juan@ejemplo.com\", \"name\": \"Juan Pérez\" }\n    ]\n  }'\n"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const id = 'doc_5Qr9tA3fZwLZmp3D1bCdEfG'\nconst res = await fetch(`https://api.allsign.io/v3/documents/${id}/send`, {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}`,\n    'Content-Type': 'application/json',\n    'Idempotency-Key': '7d1f4c8a-2e6b-4a3d-b590-8c2f7e1a6d43',\n  },\n  body: JSON.stringify({\n    recipients: [{ email: 'juan@ejemplo.com', name: 'Juan Pérez' }],\n  }),\n})\nconst document = await res.json()\n"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\ndocument_id = 'doc_5Qr9tA3fZwLZmp3D1bCdEfG'\nres = requests.post(\n    f'https://api.allsign.io/v3/documents/{document_id}/send',\n    headers={\n        'Authorization': 'Bearer allsign_live_sk_...',\n        'Idempotency-Key': '7d1f4c8a-2e6b-4a3d-b590-8c2f7e1a6d43',\n    },\n    json={'recipients': [{'email': 'juan@ejemplo.com', 'name': 'Juan Pérez'}]},\n)\ndocument = res.json()\n"
          }
        ]
      }
    },
    "/documents/{document_id}/signers": {
      "get": {
        "tags": [
          "Documents"
        ],
        "summary": "List signers",
        "operationId": "listDocumentSigners",
        "security": [
          {
            "Bearer Token": []
          }
        ],
        "parameters": [
          {
            "name": "document_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Document Id"
            },
            "description": "ID del documento (`doc_…`)."
          }
        ],
        "responses": {
          "200": {
            "description": "Colección acotada (`object: \"list\"`, `hasMore` siempre `false`) con los firmantes.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SignerList"
                },
                "example": {
                  "object": "list",
                  "data": [
                    {
                      "object": "signer",
                      "id": "sgr_a1b2c3d4e5f6a7b8",
                      "livemode": true,
                      "documentId": "doc_5Qr9tA3fZwLZmp3D1bCdEfG",
                      "name": "Juan Pérez",
                      "email": "juan@ejemplo.com",
                      "phone": null,
                      "status": "signed",
                      "signedAt": "2026-07-11T20:15:00Z"
                    },
                    {
                      "object": "signer",
                      "id": "sgr_b2c3d4e5f6a7b8c9",
                      "livemode": true,
                      "documentId": "doc_5Qr9tA3fZwLZmp3D1bCdEfG",
                      "name": "María López",
                      "email": "maria@ejemplo.com",
                      "phone": null,
                      "status": "sent",
                      "signedAt": null
                    }
                  ],
                  "hasMore": false,
                  "nextCursor": null,
                  "previousCursor": null,
                  "limit": null
                }
              }
            }
          },
          "400": {
            "description": "El identificador en un parámetro está mal formado (`INVALID_ID`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "INVALID_ID": {
                    "summary": "Malformed identifier",
                    "value": {
                      "type": "https://developers.allsign.io/errors#INVALID_ID",
                      "title": "Malformed identifier",
                      "status": 400,
                      "detail": "Invalid id; expected a typed, prefixed id (e.g. 'doc_…').",
                      "code": "INVALID_ID"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Falta el header `Authorization` o la API key no es válida.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "AUTHENTICATION_REQUIRED": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#AUTHENTICATION_REQUIRED",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "Provide an API key via Authorization: Bearer allsign_live_sk_….",
                      "code": "AUTHENTICATION_REQUIRED"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La API key no tiene el scope requerido para este recurso.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "PERMISSION_DENIED": {
                    "summary": "Permission denied",
                    "value": {
                      "type": "https://developers.allsign.io/errors#PERMISSION_DENIED",
                      "title": "Permission denied",
                      "status": 403,
                      "detail": "This API key is missing the required scope.",
                      "code": "PERMISSION_DENIED",
                      "requiredScope": "document:write",
                      "yourScopes": [
                        "document:read"
                      ]
                    }
                  },
                  "IP_NOT_ALLOWED": {
                    "summary": "IP address not allowed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IP_NOT_ALLOWED",
                      "title": "IP address not allowed",
                      "status": 403,
                      "detail": "Access from this IP is not allowed for this API key.",
                      "code": "IP_NOT_ALLOWED"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No existe un documento con ese `id` en este entorno (`DOCUMENT_NOT_FOUND`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "DOCUMENT_NOT_FOUND": {
                    "summary": "Document not found",
                    "value": {
                      "type": "https://developers.allsign.io/errors#DOCUMENT_NOT_FOUND",
                      "title": "Document not found",
                      "status": 404,
                      "detail": "No document was found with that id.",
                      "code": "DOCUMENT_NOT_FOUND"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "El parámetro no pasa la validación (ej. `period` con un valor fuera del catálogo).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Se superó el límite de tasa de tu API key; reintenta respetando `RateLimit-*` / `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          }
        },
        "description": "Lista los firmantes de un documento. Es una colección acotada (no paginada por cursor).",
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL",
            "source": "curl \"https://api.allsign.io/v3/documents/doc_5Qr9tA3fZwLZmp3D1bCdEfG/signers\" \\\n  -H \"Authorization: Bearer allsign_live_sk_...\"\n"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const id = 'doc_5Qr9tA3fZwLZmp3D1bCdEfG'\nconst res = await fetch(\n  `https://api.allsign.io/v3/documents/${id}/signers`,\n  { headers: { Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}` } },\n)\nconst { data: signers } = await res.json()\n"
          }
        ]
      }
    },
    "/documents/{document_id}/signers/{signer_id}/remind": {
      "post": {
        "tags": [
          "Documents"
        ],
        "summary": "Remind signer",
        "description": "Reenvía la invitación (email o WhatsApp, según cómo se agregó el firmante) a UN firmante que todavía no completa. Limitado a un recordatorio cada 4 horas por firmante — no lleva `Idempotency-Key` propio porque este throttle server-side ya cumple ese rol: un reintento dentro de la ventana simplemente responde 429, nunca reenvía dos veces.",
        "operationId": "remindSigner",
        "security": [
          {
            "Bearer Token": []
          }
        ],
        "parameters": [
          {
            "name": "document_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Document Id"
            },
            "description": "ID del documento (`doc_…`)."
          },
          {
            "name": "signer_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Signer Id"
            },
            "description": "ID del firmante a recordar (`sgr_…`)."
          }
        ],
        "responses": {
          "200": {
            "description": "Confirmación del recordatorio — incluye `nextAllowedAt`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RemindResponse"
                },
                "example": {
                  "documentId": "doc_5Qr9tA3fZwLZmp3D1bCdEfG",
                  "signerId": "sgr_b2c3d4e5f6a7b8c9",
                  "sentAt": "2026-07-15T14:00:00Z",
                  "nextAllowedAt": "2026-07-15T18:00:00Z",
                  "channel": "email",
                  "delivered": true
                }
              }
            }
          },
          "400": {
            "description": "El identificador en un parámetro está mal formado (`INVALID_ID`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "INVALID_ID": {
                    "summary": "Malformed identifier",
                    "value": {
                      "type": "https://developers.allsign.io/errors#INVALID_ID",
                      "title": "Malformed identifier",
                      "status": 400,
                      "detail": "Invalid id; expected a typed, prefixed id (e.g. 'doc_…').",
                      "code": "INVALID_ID"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Falta el header `Authorization` o la API key no es válida.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "AUTHENTICATION_REQUIRED": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#AUTHENTICATION_REQUIRED",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "Provide an API key via Authorization: Bearer allsign_live_sk_….",
                      "code": "AUTHENTICATION_REQUIRED"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La API key no tiene el scope requerido para este recurso.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "PERMISSION_DENIED": {
                    "summary": "Permission denied",
                    "value": {
                      "type": "https://developers.allsign.io/errors#PERMISSION_DENIED",
                      "title": "Permission denied",
                      "status": 403,
                      "detail": "This API key is missing the required scope.",
                      "code": "PERMISSION_DENIED",
                      "requiredScope": "document:write",
                      "yourScopes": [
                        "document:read"
                      ]
                    }
                  },
                  "IP_NOT_ALLOWED": {
                    "summary": "IP address not allowed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IP_NOT_ALLOWED",
                      "title": "IP address not allowed",
                      "status": 403,
                      "detail": "Access from this IP is not allowed for this API key.",
                      "code": "IP_NOT_ALLOWED"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No existe el documento o el firmante en este entorno (`DOCUMENT_NOT_FOUND` / `SIGNER_NOT_FOUND`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "DOCUMENT_NOT_FOUND": {
                    "summary": "Document not found",
                    "value": {
                      "type": "https://developers.allsign.io/errors#DOCUMENT_NOT_FOUND",
                      "title": "Document not found",
                      "status": 404,
                      "detail": "No document was found with that id.",
                      "code": "DOCUMENT_NOT_FOUND"
                    }
                  },
                  "SIGNER_NOT_FOUND": {
                    "summary": "Not Found",
                    "value": {
                      "type": "https://developers.allsign.io/errors#SIGNER_NOT_FOUND",
                      "title": "Not Found",
                      "status": 404,
                      "detail": "Not Found",
                      "code": "SIGNER_NOT_FOUND"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "El firmante ya está en un estado terminal (firmó, rechazó o expiró) — no admite recordatorio (`INVALID_STATE_TRANSITION`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "INVALID_STATE_TRANSITION": {
                    "summary": "Conflict",
                    "value": {
                      "type": "https://developers.allsign.io/errors#INVALID_STATE_TRANSITION",
                      "title": "Conflict",
                      "status": 409,
                      "detail": "Conflict",
                      "code": "INVALID_STATE_TRANSITION"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Ya se envió un recordatorio a este firmante en las últimas 4 horas (`RATE_LIMITED`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL",
            "source": "curl -X POST \"https://api.allsign.io/v3/documents/doc_5Qr9tA3fZwLZmp3D1bCdEfG/signers/sgr_b2c3d4e5f6a7b8c9/remind\" \\\n  -H \"Authorization: Bearer allsign_live_sk_...\"\n"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const documentId = 'doc_5Qr9tA3fZwLZmp3D1bCdEfG'\nconst signerId = 'sgr_b2c3d4e5f6a7b8c9'\nconst res = await fetch(\n  `https://api.allsign.io/v3/documents/${documentId}/signers/${signerId}/remind`,\n  { method: 'POST', headers: { Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}` } },\n)\nconst { nextAllowedAt } = await res.json()\n"
          }
        ]
      }
    },
    "/documents/{document_id}/events": {
      "get": {
        "tags": [
          "Documents"
        ],
        "summary": "List events",
        "operationId": "listDocumentEvents",
        "security": [
          {
            "Bearer Token": []
          }
        ],
        "parameters": [
          {
            "name": "document_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Document Id"
            },
            "description": "ID del documento (`doc_…`)."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 100,
              "minimum": 1,
              "default": 20,
              "title": "Limit"
            },
            "description": "Resultados por página (1–100, default `20`)."
          },
          {
            "name": "startingAfter",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Startingafter"
            },
            "description": "Cursor: eventos después de este `id` (`evt_…`)."
          },
          {
            "name": "endingBefore",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Endingbefore"
            },
            "description": "Cursor: eventos antes de este `id` (`evt_…`)."
          }
        ],
        "responses": {
          "200": {
            "description": "Sobre de paginación por cursor con la bitácora de eventos del documento.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventList"
                },
                "example": {
                  "object": "list",
                  "data": [
                    {
                      "object": "event",
                      "id": "evt_0a1b2c3d4e5f6a7b",
                      "livemode": true,
                      "type": "document.created",
                      "documentId": "doc_5Qr9tA3fZwLZmp3D1bCdEfG",
                      "signatureId": null,
                      "actorType": "api_key",
                      "success": true,
                      "message": "Documento creado vía API",
                      "data": {
                        "source": "template"
                      },
                      "createdAt": "2026-07-12T15:00:00Z"
                    }
                  ],
                  "hasMore": false,
                  "limit": 20,
                  "nextCursor": null,
                  "previousCursor": null
                }
              }
            }
          },
          "400": {
            "description": "El identificador en un parámetro está mal formado (`INVALID_ID`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "INVALID_ID": {
                    "summary": "Malformed identifier",
                    "value": {
                      "type": "https://developers.allsign.io/errors#INVALID_ID",
                      "title": "Malformed identifier",
                      "status": 400,
                      "detail": "Invalid id; expected a typed, prefixed id (e.g. 'doc_…').",
                      "code": "INVALID_ID"
                    }
                  },
                  "INVALID_CURSOR": {
                    "summary": "Invalid cursor",
                    "value": {
                      "type": "https://developers.allsign.io/errors#INVALID_CURSOR",
                      "title": "Invalid cursor",
                      "status": 400,
                      "detail": "The pagination cursor is malformed.",
                      "code": "INVALID_CURSOR"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Falta el header `Authorization` o la API key no es válida.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "AUTHENTICATION_REQUIRED": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#AUTHENTICATION_REQUIRED",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "Provide an API key via Authorization: Bearer allsign_live_sk_….",
                      "code": "AUTHENTICATION_REQUIRED"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La API key no tiene el scope requerido para este recurso.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "PERMISSION_DENIED": {
                    "summary": "Permission denied",
                    "value": {
                      "type": "https://developers.allsign.io/errors#PERMISSION_DENIED",
                      "title": "Permission denied",
                      "status": 403,
                      "detail": "This API key is missing the required scope.",
                      "code": "PERMISSION_DENIED",
                      "requiredScope": "document:write",
                      "yourScopes": [
                        "document:read"
                      ]
                    }
                  },
                  "IP_NOT_ALLOWED": {
                    "summary": "IP address not allowed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IP_NOT_ALLOWED",
                      "title": "IP address not allowed",
                      "status": 403,
                      "detail": "Access from this IP is not allowed for this API key.",
                      "code": "IP_NOT_ALLOWED"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No existe un documento con ese `id` en este entorno (`DOCUMENT_NOT_FOUND`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "DOCUMENT_NOT_FOUND": {
                    "summary": "Document not found",
                    "value": {
                      "type": "https://developers.allsign.io/errors#DOCUMENT_NOT_FOUND",
                      "title": "Document not found",
                      "status": 404,
                      "detail": "No document was found with that id.",
                      "code": "DOCUMENT_NOT_FOUND"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "El parámetro no pasa la validación (ej. `period` con un valor fuera del catálogo).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "VALIDATION_ERROR": {
                    "summary": "Validation failed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#VALIDATION_ERROR",
                      "title": "Validation failed",
                      "status": 422,
                      "detail": "One or more fields are invalid.",
                      "code": "VALIDATION_ERROR"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Se superó el límite de tasa de tu API key; reintenta respetando `RateLimit-*` / `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          }
        },
        "description": "Lista la bitácora de eventos de un documento (creación, envío, firmas, etc.), paginada por cursor. `type` es un token del catálogo de eventos con namespace punteado `recurso.enPasado` (ej. `document.created`).",
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL",
            "source": "curl \"https://api.allsign.io/v3/documents/doc_5Qr9tA3fZwLZmp3D1bCdEfG/events?limit=20\" \\\n  -H \"Authorization: Bearer allsign_live_sk_...\"\n"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const id = 'doc_5Qr9tA3fZwLZmp3D1bCdEfG'\nconst res = await fetch(\n  `https://api.allsign.io/v3/documents/${id}/events?limit=20`,\n  { headers: { Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}` } },\n)\nconst { data: events, hasMore } = await res.json()\n"
          }
        ]
      }
    },
    "/documents/{document_id}/void": {
      "post": {
        "tags": [
          "Documents"
        ],
        "summary": "Void document",
        "description": "Anula (invalida) un documento. **No es un DELETE**: la retención NOM-151 conserva el registro, por eso anular es una operación explícita que deja el documento en `voided`. Puedes incluir una `reason` opcional. Una anulación legítima puede cancelar cero firmas — el resultado se decide por el `status`, no por cuántas firmas se cancelaron.",
        "operationId": "voidDocument",
        "security": [
          {
            "Bearer Token": []
          }
        ],
        "parameters": [
          {
            "name": "document_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Document Id"
            },
            "description": "ID del documento (`doc_…`)."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VoidRequest"
              },
              "example": {
                "reason": "Cliente canceló la operación"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "El Document; su `status` queda en `voided`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Document"
                },
                "example": {
                  "object": "document",
                  "id": "doc_5Qr9tA3fZwLZmp3D1bCdEfG",
                  "livemode": true,
                  "name": "Contrato de arrendamiento 2026.pdf",
                  "status": "voided",
                  "documentType": "editable",
                  "signerCount": 2,
                  "signedCount": 1,
                  "ownerId": "usr_1a2b3c4d5e6f7g8h",
                  "orgId": "org_9i8u7y6t5r4e3w2q",
                  "folderId": null,
                  "expiresAt": null,
                  "expirationReminders": null,
                  "createdAt": "2026-07-11T18:04:00Z",
                  "updatedAt": "2026-07-12T16:20:00Z"
                }
              }
            }
          },
          "400": {
            "description": "El identificador en un parámetro está mal formado (`INVALID_ID`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "INVALID_ID": {
                    "summary": "Malformed identifier",
                    "value": {
                      "type": "https://developers.allsign.io/errors#INVALID_ID",
                      "title": "Malformed identifier",
                      "status": 400,
                      "detail": "Invalid id; expected a typed, prefixed id (e.g. 'doc_…').",
                      "code": "INVALID_ID"
                    }
                  },
                  "IDEMPOTENCY_KEY_REQUIRED": {
                    "summary": "Idempotency key required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IDEMPOTENCY_KEY_REQUIRED",
                      "title": "Idempotency key required",
                      "status": 400,
                      "detail": "POST requests that create or charge require a unique Idempotency-Key (UUID v4).",
                      "code": "IDEMPOTENCY_KEY_REQUIRED"
                    }
                  },
                  "IDEMPOTENCY_KEY_INVALID": {
                    "summary": "Idempotency key invalid",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IDEMPOTENCY_KEY_INVALID",
                      "title": "Idempotency key invalid",
                      "status": 400,
                      "detail": "Idempotency-Key must be a UUID v4.",
                      "code": "IDEMPOTENCY_KEY_INVALID"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Falta el header `Authorization` o la API key no es válida.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "AUTHENTICATION_REQUIRED": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#AUTHENTICATION_REQUIRED",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "Provide an API key via Authorization: Bearer allsign_live_sk_….",
                      "code": "AUTHENTICATION_REQUIRED"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La API key no tiene el scope requerido para este recurso.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "PERMISSION_DENIED": {
                    "summary": "Permission denied",
                    "value": {
                      "type": "https://developers.allsign.io/errors#PERMISSION_DENIED",
                      "title": "Permission denied",
                      "status": 403,
                      "detail": "This API key is missing the required scope.",
                      "code": "PERMISSION_DENIED",
                      "requiredScope": "document:write",
                      "yourScopes": [
                        "document:read"
                      ]
                    }
                  },
                  "IP_NOT_ALLOWED": {
                    "summary": "IP address not allowed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IP_NOT_ALLOWED",
                      "title": "IP address not allowed",
                      "status": 403,
                      "detail": "Access from this IP is not allowed for this API key.",
                      "code": "IP_NOT_ALLOWED"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No existe un documento con ese `id` en este entorno (`DOCUMENT_NOT_FOUND`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "DOCUMENT_NOT_FOUND": {
                    "summary": "Document not found",
                    "value": {
                      "type": "https://developers.allsign.io/errors#DOCUMENT_NOT_FOUND",
                      "title": "Document not found",
                      "status": 404,
                      "detail": "No document was found with that id.",
                      "code": "DOCUMENT_NOT_FOUND"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "El documento ya está `voided` o en un estado que no admite anulación.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "DOCUMENT_ALREADY_SIGNED": {
                    "summary": "Document already signed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#DOCUMENT_ALREADY_SIGNED",
                      "title": "Document already signed",
                      "status": 409,
                      "detail": "The document is already fully signed.",
                      "code": "DOCUMENT_ALREADY_SIGNED"
                    }
                  },
                  "DOCUMENT_CONFLICT": {
                    "summary": "Document conflict",
                    "value": {
                      "type": "https://developers.allsign.io/errors#DOCUMENT_CONFLICT",
                      "title": "Document conflict",
                      "status": 409,
                      "detail": "The document is not in a state that allows this operation.",
                      "code": "DOCUMENT_CONFLICT"
                    }
                  },
                  "IDEMPOTENCY_KEY_REUSED": {
                    "summary": "Idempotency key reused",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IDEMPOTENCY_KEY_REUSED",
                      "title": "Idempotency key reused",
                      "status": 409,
                      "detail": "This Idempotency-Key was already used with a different request.",
                      "code": "IDEMPOTENCY_KEY_REUSED"
                    }
                  },
                  "IDEMPOTENCY_KEY_IN_PROGRESS": {
                    "summary": "Idempotency key in progress",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IDEMPOTENCY_KEY_IN_PROGRESS",
                      "title": "Idempotency key in progress",
                      "status": 409,
                      "detail": "A request with this Idempotency-Key is still in progress.",
                      "code": "IDEMPOTENCY_KEY_IN_PROGRESS",
                      "retryAfter": 2
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "El parámetro no pasa la validación (ej. `period` con un valor fuera del catálogo).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "VALIDATION_ERROR": {
                    "summary": "Validation failed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#VALIDATION_ERROR",
                      "title": "Validation failed",
                      "status": 422,
                      "detail": "One or more fields are invalid.",
                      "code": "VALIDATION_ERROR"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Se superó el límite de tasa de tu API key; reintenta respetando `RateLimit-*` / `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL",
            "source": "curl \"https://api.allsign.io/v3/documents/doc_5Qr9tA3fZwLZmp3D1bCdEfG/void\" \\\n  -H \"Authorization: Bearer allsign_live_sk_...\" \\\n  -H \"Content-Type: application/json\" \\\n  -H \"Idempotency-Key: c4a91e7f-6b2d-4f8e-a1c3-9d5b0f7e2a86\" \\\n  -d '{ \"reason\": \"Cliente canceló la operación\" }'\n"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const id = 'doc_5Qr9tA3fZwLZmp3D1bCdEfG'\nconst res = await fetch(`https://api.allsign.io/v3/documents/${id}/void`, {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}`,\n    'Content-Type': 'application/json',\n    'Idempotency-Key': 'c4a91e7f-6b2d-4f8e-a1c3-9d5b0f7e2a86',\n  },\n  body: JSON.stringify({ reason: 'Cliente canceló la operación' }),\n})\nconst document = await res.json()\n"
          }
        ]
      }
    },
    "/documents/{document_id}/evidence": {
      "get": {
        "tags": [
          "Documents"
        ],
        "summary": "Get evidence bundle",
        "description": "Los 2 archivos de respaldo de un documento: el PDF sellado con todas las firmas (`evidencePdf`) y la constancia de conservación NOM-151 (`nom151`, `null` si el documento no es `livemode`). Ambos son `null` hasta que **todos** los firmantes completan — el workflow de Temporal que los genera termina unos segundos después de la última firma, así que haz *poll* de `available` en vez de asumir que ya existen justo al completarse el flujo.",
        "operationId": "getDocumentEvidence",
        "security": [
          {
            "Bearer Token": []
          }
        ],
        "parameters": [
          {
            "name": "document_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Document Id"
            },
            "description": "ID del documento (`doc_…`)."
          }
        ],
        "responses": {
          "200": {
            "description": "El bundle de evidencia — `available` indica si ya están listos los archivos.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentEvidence"
                },
                "example": {
                  "documentId": "doc_5Qr9tA3fZwLZmp3D1bCdEfG",
                  "available": true,
                  "evidencePdf": {
                    "url": "https://evidence.allsign.io/doc_5Qr9tA3fZwLZmp3D1bCdEfG/evidence.pdf?sig=...",
                    "sha256": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"
                  },
                  "nom151": {
                    "url": "https://evidence.allsign.io/doc_5Qr9tA3fZwLZmp3D1bCdEfG/nom151.pdf?sig=...",
                    "sha256": "a3f1e0b8c9d2e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9"
                  }
                }
              }
            }
          },
          "400": {
            "description": "El identificador en un parámetro está mal formado (`INVALID_ID`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "INVALID_ID": {
                    "summary": "Malformed identifier",
                    "value": {
                      "type": "https://developers.allsign.io/errors#INVALID_ID",
                      "title": "Malformed identifier",
                      "status": 400,
                      "detail": "Invalid id; expected a typed, prefixed id (e.g. 'doc_…').",
                      "code": "INVALID_ID"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Falta el header `Authorization` o la API key no es válida.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "AUTHENTICATION_REQUIRED": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#AUTHENTICATION_REQUIRED",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "Provide an API key via Authorization: Bearer allsign_live_sk_….",
                      "code": "AUTHENTICATION_REQUIRED"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La API key no tiene el scope requerido para este recurso.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "PERMISSION_DENIED": {
                    "summary": "Permission denied",
                    "value": {
                      "type": "https://developers.allsign.io/errors#PERMISSION_DENIED",
                      "title": "Permission denied",
                      "status": 403,
                      "detail": "This API key is missing the required scope.",
                      "code": "PERMISSION_DENIED",
                      "requiredScope": "document:write",
                      "yourScopes": [
                        "document:read"
                      ]
                    }
                  },
                  "IP_NOT_ALLOWED": {
                    "summary": "IP address not allowed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IP_NOT_ALLOWED",
                      "title": "IP address not allowed",
                      "status": 403,
                      "detail": "Access from this IP is not allowed for this API key.",
                      "code": "IP_NOT_ALLOWED"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No existe un documento con ese `id` en este entorno (`DOCUMENT_NOT_FOUND`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "DOCUMENT_NOT_FOUND": {
                    "summary": "Document not found",
                    "value": {
                      "type": "https://developers.allsign.io/errors#DOCUMENT_NOT_FOUND",
                      "title": "Document not found",
                      "status": 404,
                      "detail": "No document was found with that id.",
                      "code": "DOCUMENT_NOT_FOUND"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Se superó el límite de tasa de tu API key; reintenta respetando `RateLimit-*` / `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL",
            "source": "curl \"https://api.allsign.io/v3/documents/doc_5Qr9tA3fZwLZmp3D1bCdEfG/evidence\" \\\n  -H \"Authorization: Bearer allsign_live_sk_...\"\n"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const id = 'doc_5Qr9tA3fZwLZmp3D1bCdEfG'\nconst res = await fetch(\n  `https://api.allsign.io/v3/documents/${id}/evidence`,\n  { headers: { Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}` } },\n)\nconst { available, evidencePdf, nom151 } = await res.json()\n"
          }
        ]
      }
    },
    "/documents/bulk": {
      "delete": {
        "tags": [
          "Documents"
        ],
        "summary": "Bulk delete documents",
        "description": "Elimina hasta 100 documentos en una sola petición. Éxito parcial por diseño (igual que v2): un id mal formado, un id de otro tenant, o un documento en un estado no eliminable (ya firmado o en progreso) falla SOLO ese elemento — nunca todo el lote. Revisa `items[].status` por cada id, nunca asumas éxito total por un `200`.",
        "operationId": "bulkDeleteDocuments",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BulkDeleteRequest"
              },
              "example": {
                "documentIds": [
                  "doc_3Nk8sZ2eZvKYlo2C0aBcDeF",
                  "doc_5Qr9tA3fZwLZmp3D1bCdEfG"
                ]
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Resultado por elemento (`totalCount`/`successCount`/`errorCount`/`items[]`) — mismo vocabulario que Create bulk send.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkDeleteResponse"
                },
                "example": {
                  "totalCount": 2,
                  "successCount": 1,
                  "errorCount": 1,
                  "items": [
                    {
                      "documentId": "doc_3Nk8sZ2eZvKYlo2C0aBcDeF",
                      "status": "deleted",
                      "error": null
                    },
                    {
                      "documentId": "doc_5Qr9tA3fZwLZmp3D1bCdEfG",
                      "status": "error",
                      "error": "Document is already signed."
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Falta el header `Authorization` o la API key no es válida.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "AUTHENTICATION_REQUIRED": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#AUTHENTICATION_REQUIRED",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "Provide an API key via Authorization: Bearer allsign_live_sk_….",
                      "code": "AUTHENTICATION_REQUIRED"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La API key no tiene el scope `document:delete`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "PERMISSION_DENIED": {
                    "summary": "Permission denied",
                    "value": {
                      "type": "https://developers.allsign.io/errors#PERMISSION_DENIED",
                      "title": "Permission denied",
                      "status": 403,
                      "detail": "This API key is missing the required scope.",
                      "code": "PERMISSION_DENIED",
                      "requiredScope": "document:write",
                      "yourScopes": [
                        "document:read"
                      ]
                    }
                  },
                  "IP_NOT_ALLOWED": {
                    "summary": "IP address not allowed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IP_NOT_ALLOWED",
                      "title": "IP address not allowed",
                      "status": 403,
                      "detail": "Access from this IP is not allowed for this API key.",
                      "code": "IP_NOT_ALLOWED"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "El parámetro no pasa la validación (ej. `period` con un valor fuera del catálogo).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "VALIDATION_ERROR": {
                    "summary": "Validation failed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#VALIDATION_ERROR",
                      "title": "Validation failed",
                      "status": 422,
                      "detail": "One or more fields are invalid.",
                      "code": "VALIDATION_ERROR"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Se superó el límite de tasa de tu API key; reintenta respetando `RateLimit-*` / `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer Token": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL",
            "source": "curl -X DELETE \"https://api.allsign.io/v3/documents/bulk\" \\\n  -H \"Authorization: Bearer allsign_live_sk_...\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{ \"documentIds\": [\"doc_3Nk8sZ2eZvKYlo2C0aBcDeF\", \"doc_5Qr9tA3fZwLZmp3D1bCdEfG\"] }'\n"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const res = await fetch('https://api.allsign.io/v3/documents/bulk', {\n  method: 'DELETE',\n  headers: {\n    Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    documentIds: ['doc_3Nk8sZ2eZvKYlo2C0aBcDeF', 'doc_5Qr9tA3fZwLZmp3D1bCdEfG'],\n  }),\n})\nconst { items } = await res.json()\n"
          }
        ]
      }
    },
    "/webhooks": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Create endpoint",
        "description": "Registra un endpoint firmado. Genera un secreto `whsec_` (**devuelto una sola vez**), fuerza HMAC, y estampa la versión de contrato con fecha (`apiVersion`) + el entorno de la key — no hay cruce `live`/`test`. Requiere `webhook:write`.",
        "operationId": "createWebhookEndpoint",
        "security": [
          {
            "Bearer Token": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEndpointCreate"
              },
              "example": {
                "url": "https://tu-servidor.com/webhooks/allsign",
                "events": [
                  "document.completed",
                  "document.voided"
                ],
                "description": "Integración de contratos"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "El endpoint creado, con el `secret` en claro (única vez).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookEndpointCreatedResponse"
                },
                "example": {
                  "object": "webhook_endpoint",
                  "id": "whe_7c9e6679742540de944be07fc1f90ae7",
                  "secret": "whsec_9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822c",
                  "secretLast4": "822c",
                  "url": "https://tu-servidor.com/webhooks/allsign",
                  "events": [
                    "document.completed",
                    "document.voided"
                  ],
                  "status": "enabled",
                  "apiVersion": "2026-07-11",
                  "environment": "live",
                  "livemode": true,
                  "description": "Integración de contratos",
                  "createdAt": "2026-07-11T18:04:00Z"
                }
              }
            }
          },
          "400": {
            "description": "La URL no es `https://`, mal formada, u otro campo inválido.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "IDEMPOTENCY_KEY_INVALID": {
                    "summary": "Idempotency key invalid",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IDEMPOTENCY_KEY_INVALID",
                      "title": "Idempotency key invalid",
                      "status": 400,
                      "detail": "Idempotency-Key must be a UUID v4.",
                      "code": "IDEMPOTENCY_KEY_INVALID"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Falta el header `Authorization` o la API key no es válida.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "AUTHENTICATION_REQUIRED": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#AUTHENTICATION_REQUIRED",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "Provide an API key via Authorization: Bearer allsign_live_sk_….",
                      "code": "AUTHENTICATION_REQUIRED"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La API key no tiene el scope `webhook:write`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "PERMISSION_DENIED": {
                    "summary": "Permission denied",
                    "value": {
                      "type": "https://developers.allsign.io/errors#PERMISSION_DENIED",
                      "title": "Permission denied",
                      "status": 403,
                      "detail": "This API key is missing the required scope.",
                      "code": "PERMISSION_DENIED",
                      "requiredScope": "document:write",
                      "yourScopes": [
                        "document:read"
                      ]
                    }
                  },
                  "IP_NOT_ALLOWED": {
                    "summary": "IP address not allowed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IP_NOT_ALLOWED",
                      "title": "IP address not allowed",
                      "status": 403,
                      "detail": "Access from this IP is not allowed for this API key.",
                      "code": "IP_NOT_ALLOWED"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Webhook endpoint not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "WEBHOOK_NOT_FOUND": {
                    "summary": "Webhook endpoint not found",
                    "value": {
                      "type": "https://developers.allsign.io/errors#WEBHOOK_NOT_FOUND",
                      "title": "Webhook endpoint not found",
                      "status": 404,
                      "detail": "No webhook endpoint was found with that id.",
                      "code": "WEBHOOK_NOT_FOUND"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Reintento con la misma `Idempotency-Key` mientras la petición original sigue en curso.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "WEBHOOK_LIMIT_EXCEEDED": {
                    "summary": "Conflict",
                    "value": {
                      "type": "https://developers.allsign.io/errors#WEBHOOK_LIMIT_EXCEEDED",
                      "title": "Conflict",
                      "status": 409,
                      "detail": "Conflict",
                      "code": "WEBHOOK_LIMIT_EXCEEDED"
                    }
                  },
                  "IDEMPOTENCY_KEY_REUSED": {
                    "summary": "Idempotency key reused",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IDEMPOTENCY_KEY_REUSED",
                      "title": "Idempotency key reused",
                      "status": 409,
                      "detail": "This Idempotency-Key was already used with a different request.",
                      "code": "IDEMPOTENCY_KEY_REUSED"
                    }
                  },
                  "IDEMPOTENCY_KEY_IN_PROGRESS": {
                    "summary": "Idempotency key in progress",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IDEMPOTENCY_KEY_IN_PROGRESS",
                      "title": "Idempotency key in progress",
                      "status": 409,
                      "detail": "A request with this Idempotency-Key is still in progress.",
                      "code": "IDEMPOTENCY_KEY_IN_PROGRESS",
                      "retryAfter": 2
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "La URL no es `https://` (`WEBHOOK_URL_INVALID`), o un evento no existe en el catálogo (`UNKNOWN_EVENT_TYPE`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "VALIDATION_ERROR": {
                    "summary": "Validation failed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#VALIDATION_ERROR",
                      "title": "Validation failed",
                      "status": 422,
                      "detail": "One or more fields are invalid.",
                      "code": "VALIDATION_ERROR"
                    }
                  },
                  "WEBHOOK_URL_INVALID": {
                    "summary": "Webhook URL invalid",
                    "value": {
                      "type": "https://developers.allsign.io/errors#WEBHOOK_URL_INVALID",
                      "title": "Webhook URL invalid",
                      "status": 422,
                      "detail": "The webhook url must be an absolute https:// URL.",
                      "code": "WEBHOOK_URL_INVALID"
                    }
                  },
                  "UNKNOWN_EVENT_TYPE": {
                    "summary": "Unknown event type",
                    "value": {
                      "type": "https://developers.allsign.io/errors#UNKNOWN_EVENT_TYPE",
                      "title": "Unknown event type",
                      "status": 422,
                      "detail": "One or more event types are not in the v3 catalog.",
                      "code": "UNKNOWN_EVENT_TYPE"
                    }
                  }
                },
                "example": {
                  "type": "https://developers.allsign.io/errors#WEBHOOK_URL_INVALID",
                  "title": "Webhook URL invalid",
                  "status": 422,
                  "detail": "La URL del webhook debe empezar con https://.",
                  "instance": "/v3/webhooks",
                  "code": "WEBHOOK_URL_INVALID",
                  "requestId": "req_9f86d081884c7d659a2feaa0c55ad015"
                }
              }
            }
          },
          "429": {
            "description": "Se superó el límite de tasa de tu API key; reintenta respetando `RateLimit-*` / `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL",
            "source": "curl -X POST \"https://api.allsign.io/v3/webhooks\" \\\n  -H \"Authorization: Bearer allsign_live_sk_...\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"url\": \"https://tu-servidor.com/webhooks/allsign\",\n    \"events\": [\"document.completed\", \"document.voided\"],\n    \"description\": \"Integración de contratos\"\n  }'\n"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const res = await fetch('https://api.allsign.io/v3/webhooks', {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    url: 'https://tu-servidor.com/webhooks/allsign',\n    events: ['document.completed', 'document.voided'],\n  }),\n})\nconst endpoint = await res.json()\n// Guarda endpoint.secret AHORA — no se vuelve a mostrar\n"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nres = requests.post(\n    'https://api.allsign.io/v3/webhooks',\n    headers={'Authorization': 'Bearer allsign_live_sk_...'},\n    json={\n        'url': 'https://tu-servidor.com/webhooks/allsign',\n        'events': ['document.completed', 'document.voided'],\n        'description': 'Integración de contratos',\n    },\n)\nendpoint = res.json()\n# Guarda endpoint['secret'] AHORA — no se vuelve a mostrar\n"
          }
        ]
      },
      "get": {
        "tags": [
          "Webhooks"
        ],
        "summary": "List endpoints",
        "operationId": "listWebhookEndpoints",
        "security": [
          {
            "Bearer Token": []
          }
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 100,
              "minimum": 1,
              "default": 20,
              "title": "Limit"
            },
            "description": "Resultados por página (1–100, default `20`)."
          },
          {
            "name": "startingAfter",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Startingafter"
            },
            "description": "Cursor: endpoints después de este `id` (`whe_…`)."
          },
          {
            "name": "endingBefore",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Endingbefore"
            },
            "description": "Cursor: endpoints antes de este `id` (`whe_…`)."
          }
        ],
        "responses": {
          "200": {
            "description": "Sobre de paginación por cursor con los endpoints (sin el secreto, solo `secretLast4`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookEndpointList"
                },
                "example": {
                  "object": "list",
                  "data": [
                    {
                      "object": "webhook_endpoint",
                      "id": "whe_7c9e6679742540de944be07fc1f90ae7",
                      "url": "https://tu-servidor.com/webhooks/allsign",
                      "events": [
                        "document.completed",
                        "document.voided"
                      ],
                      "status": "enabled",
                      "apiVersion": "2026-07-11",
                      "environment": "live",
                      "livemode": true,
                      "secretLast4": "822c",
                      "description": "Integración de contratos",
                      "createdAt": "2026-07-11T18:04:00Z"
                    }
                  ],
                  "hasMore": false,
                  "limit": 20,
                  "nextCursor": null,
                  "previousCursor": null
                }
              }
            }
          },
          "400": {
            "description": "El identificador en un parámetro está mal formado (`INVALID_ID`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "INVALID_CURSOR": {
                    "summary": "Invalid cursor",
                    "value": {
                      "type": "https://developers.allsign.io/errors#INVALID_CURSOR",
                      "title": "Invalid cursor",
                      "status": 400,
                      "detail": "The pagination cursor is malformed.",
                      "code": "INVALID_CURSOR"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Falta el header `Authorization` o la API key no es válida.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "AUTHENTICATION_REQUIRED": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#AUTHENTICATION_REQUIRED",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "Provide an API key via Authorization: Bearer allsign_live_sk_….",
                      "code": "AUTHENTICATION_REQUIRED"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La API key no tiene el scope `webhook:read`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "PERMISSION_DENIED": {
                    "summary": "Permission denied",
                    "value": {
                      "type": "https://developers.allsign.io/errors#PERMISSION_DENIED",
                      "title": "Permission denied",
                      "status": 403,
                      "detail": "This API key is missing the required scope.",
                      "code": "PERMISSION_DENIED",
                      "requiredScope": "document:write",
                      "yourScopes": [
                        "document:read"
                      ]
                    }
                  },
                  "IP_NOT_ALLOWED": {
                    "summary": "IP address not allowed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IP_NOT_ALLOWED",
                      "title": "IP address not allowed",
                      "status": 403,
                      "detail": "Access from this IP is not allowed for this API key.",
                      "code": "IP_NOT_ALLOWED"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Webhook endpoint not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "WEBHOOK_NOT_FOUND": {
                    "summary": "Webhook endpoint not found",
                    "value": {
                      "type": "https://developers.allsign.io/errors#WEBHOOK_NOT_FOUND",
                      "title": "Webhook endpoint not found",
                      "status": 404,
                      "detail": "No webhook endpoint was found with that id.",
                      "code": "WEBHOOK_NOT_FOUND"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "El parámetro no pasa la validación (ej. `period` con un valor fuera del catálogo).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "VALIDATION_ERROR": {
                    "summary": "Validation failed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#VALIDATION_ERROR",
                      "title": "Validation failed",
                      "status": 422,
                      "detail": "One or more fields are invalid.",
                      "code": "VALIDATION_ERROR"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Se superó el límite de tasa de tu API key; reintenta respetando `RateLimit-*` / `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          }
        },
        "description": "Lista tus endpoints de webhook con paginación por cursor. **El secreto nunca aparece aquí** — solo `secretLast4`.",
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL",
            "source": "curl \"https://api.allsign.io/v3/webhooks?limit=20\" \\\n  -H \"Authorization: Bearer allsign_live_sk_...\"\n"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const res = await fetch('https://api.allsign.io/v3/webhooks?limit=20', {\n  headers: { Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}` },\n})\nconst { data, hasMore, nextCursor } = await res.json()\n"
          }
        ]
      }
    },
    "/webhooks/events": {
      "get": {
        "tags": [
          "Webhooks"
        ],
        "summary": "List events",
        "description": "El catálogo **congelado** de eventos v3 a los que puedes suscribirte — la fuente de verdad contra la que valida `POST /v3/webhooks`. Requiere `webhook:read`.",
        "operationId": "listWebhookEvents",
        "responses": {
          "200": {
            "description": "El catálogo de eventos disponibles (`active` o `reserved`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookEventCatalog"
                },
                "example": {
                  "object": "list",
                  "data": [
                    {
                      "event": "document.created",
                      "description": "A document was created via the API.",
                      "category": "Documents",
                      "apiVersion": "2026-07-11",
                      "status": "active"
                    },
                    {
                      "event": "document.completed",
                      "description": "All parties signed and the evidence PDF is ready.",
                      "category": "Documents",
                      "apiVersion": "2026-07-11",
                      "status": "active"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Falta el header `Authorization` o la API key no es válida.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "AUTHENTICATION_REQUIRED": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#AUTHENTICATION_REQUIRED",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "Provide an API key via Authorization: Bearer allsign_live_sk_….",
                      "code": "AUTHENTICATION_REQUIRED"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La API key no tiene el scope `webhook:read`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "PERMISSION_DENIED": {
                    "summary": "Permission denied",
                    "value": {
                      "type": "https://developers.allsign.io/errors#PERMISSION_DENIED",
                      "title": "Permission denied",
                      "status": 403,
                      "detail": "This API key is missing the required scope.",
                      "code": "PERMISSION_DENIED",
                      "requiredScope": "document:write",
                      "yourScopes": [
                        "document:read"
                      ]
                    }
                  },
                  "IP_NOT_ALLOWED": {
                    "summary": "IP address not allowed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IP_NOT_ALLOWED",
                      "title": "IP address not allowed",
                      "status": 403,
                      "detail": "Access from this IP is not allowed for this API key.",
                      "code": "IP_NOT_ALLOWED"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "El parámetro no pasa la validación (ej. `period` con un valor fuera del catálogo).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Se superó el límite de tasa de tu API key; reintenta respetando `RateLimit-*` / `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer Token": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL",
            "source": "curl \"https://api.allsign.io/v3/webhooks/events\" \\\n  -H \"Authorization: Bearer allsign_live_sk_...\"\n"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const res = await fetch('https://api.allsign.io/v3/webhooks/events', {\n  headers: { Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}` },\n})\nconst { data: catalog } = await res.json()\n"
          }
        ]
      }
    },
    "/webhooks/{webhook_id}": {
      "get": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Retrieve endpoint",
        "operationId": "getWebhookEndpoint",
        "security": [
          {
            "Bearer Token": []
          }
        ],
        "parameters": [
          {
            "name": "webhook_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Webhook Id"
            },
            "description": "ID del endpoint (`whe_…`)."
          }
        ],
        "responses": {
          "200": {
            "description": "El endpoint (sin secreto, solo `secretLast4`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookEndpointResponse"
                },
                "example": {
                  "object": "webhook_endpoint",
                  "id": "whe_7c9e6679742540de944be07fc1f90ae7",
                  "url": "https://tu-servidor.com/webhooks/allsign",
                  "events": [
                    "document.completed",
                    "document.voided"
                  ],
                  "status": "enabled",
                  "apiVersion": "2026-07-11",
                  "environment": "live",
                  "secretLast4": "822c",
                  "description": "Integración de contratos",
                  "livemode": true,
                  "createdAt": "2026-07-11T18:04:00Z"
                }
              }
            }
          },
          "400": {
            "description": "El identificador en un parámetro está mal formado (`INVALID_ID`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "INVALID_ID": {
                    "summary": "Malformed identifier",
                    "value": {
                      "type": "https://developers.allsign.io/errors#INVALID_ID",
                      "title": "Malformed identifier",
                      "status": 400,
                      "detail": "Invalid id; expected a typed, prefixed id (e.g. 'doc_…').",
                      "code": "INVALID_ID"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Falta el header `Authorization` o la API key no es válida.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "AUTHENTICATION_REQUIRED": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#AUTHENTICATION_REQUIRED",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "Provide an API key via Authorization: Bearer allsign_live_sk_….",
                      "code": "AUTHENTICATION_REQUIRED"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La API key no tiene el scope `webhook:read`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "PERMISSION_DENIED": {
                    "summary": "Permission denied",
                    "value": {
                      "type": "https://developers.allsign.io/errors#PERMISSION_DENIED",
                      "title": "Permission denied",
                      "status": 403,
                      "detail": "This API key is missing the required scope.",
                      "code": "PERMISSION_DENIED",
                      "requiredScope": "document:write",
                      "yourScopes": [
                        "document:read"
                      ]
                    }
                  },
                  "IP_NOT_ALLOWED": {
                    "summary": "IP address not allowed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IP_NOT_ALLOWED",
                      "title": "IP address not allowed",
                      "status": 403,
                      "detail": "Access from this IP is not allowed for this API key.",
                      "code": "IP_NOT_ALLOWED"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No existe un endpoint con ese `id` en este tenant (`WEBHOOK_NOT_FOUND`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "WEBHOOK_NOT_FOUND": {
                    "summary": "Webhook endpoint not found",
                    "value": {
                      "type": "https://developers.allsign.io/errors#WEBHOOK_NOT_FOUND",
                      "title": "Webhook endpoint not found",
                      "status": 404,
                      "detail": "No webhook endpoint was found with that id.",
                      "code": "WEBHOOK_NOT_FOUND"
                    }
                  }
                },
                "example": {
                  "type": "about:blank",
                  "title": "Webhook not found",
                  "status": 404,
                  "code": "WEBHOOK_NOT_FOUND",
                  "detail": "No existe un endpoint con ese id en este tenant."
                }
              }
            }
          },
          "422": {
            "description": "El parámetro no pasa la validación (ej. `period` con un valor fuera del catálogo).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Se superó el límite de tasa de tu API key; reintenta respetando `RateLimit-*` / `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          }
        },
        "description": "Consulta un endpoint por su `id`. No incluye el secreto (solo `secretLast4`). Un `id` inexistente o de otro tenant responde **404 `WEBHOOK_NOT_FOUND`**.",
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL",
            "source": "curl \"https://api.allsign.io/v3/webhooks/whe_7c9e6679742540de944be07fc1f90ae7\" \\\n  -H \"Authorization: Bearer allsign_live_sk_...\"\n"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const id = 'whe_7c9e6679742540de944be07fc1f90ae7'\nconst res = await fetch(`https://api.allsign.io/v3/webhooks/${id}`, {\n  headers: { Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}` },\n})\nconst endpoint = await res.json()\n"
          }
        ]
      },
      "patch": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Update endpoint",
        "operationId": "updateWebhookEndpoint",
        "security": [
          {
            "Bearer Token": []
          }
        ],
        "parameters": [
          {
            "name": "webhook_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Webhook Id"
            },
            "description": "ID del endpoint (`whe_…`)."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEndpointUpdate"
              },
              "example": {
                "events": [
                  "document.completed"
                ],
                "disabled": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "El endpoint actualizado (mismo shape que Retrieve endpoint).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookEndpointResponse"
                },
                "example": {
                  "object": "webhook_endpoint",
                  "id": "whe_7c9e6679742540de944be07fc1f90ae7",
                  "url": "https://tu-servidor.com/webhooks/allsign",
                  "events": [
                    "document.completed"
                  ],
                  "status": "enabled",
                  "apiVersion": "2026-07-11",
                  "environment": "live",
                  "secretLast4": "822c",
                  "description": "Integración de contratos",
                  "livemode": true,
                  "createdAt": "2026-07-11T18:04:00Z"
                }
              }
            }
          },
          "400": {
            "description": "El identificador en un parámetro está mal formado (`INVALID_ID`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "INVALID_ID": {
                    "summary": "Malformed identifier",
                    "value": {
                      "type": "https://developers.allsign.io/errors#INVALID_ID",
                      "title": "Malformed identifier",
                      "status": 400,
                      "detail": "Invalid id; expected a typed, prefixed id (e.g. 'doc_…').",
                      "code": "INVALID_ID"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Falta el header `Authorization` o la API key no es válida.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "AUTHENTICATION_REQUIRED": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#AUTHENTICATION_REQUIRED",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "Provide an API key via Authorization: Bearer allsign_live_sk_….",
                      "code": "AUTHENTICATION_REQUIRED"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La API key no tiene el scope `webhook:write`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "PERMISSION_DENIED": {
                    "summary": "Permission denied",
                    "value": {
                      "type": "https://developers.allsign.io/errors#PERMISSION_DENIED",
                      "title": "Permission denied",
                      "status": 403,
                      "detail": "This API key is missing the required scope.",
                      "code": "PERMISSION_DENIED",
                      "requiredScope": "document:write",
                      "yourScopes": [
                        "document:read"
                      ]
                    }
                  },
                  "IP_NOT_ALLOWED": {
                    "summary": "IP address not allowed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IP_NOT_ALLOWED",
                      "title": "IP address not allowed",
                      "status": 403,
                      "detail": "Access from this IP is not allowed for this API key.",
                      "code": "IP_NOT_ALLOWED"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No existe un endpoint con ese `id` en este tenant (`WEBHOOK_NOT_FOUND`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "WEBHOOK_NOT_FOUND": {
                    "summary": "Webhook endpoint not found",
                    "value": {
                      "type": "https://developers.allsign.io/errors#WEBHOOK_NOT_FOUND",
                      "title": "Webhook endpoint not found",
                      "status": 404,
                      "detail": "No webhook endpoint was found with that id.",
                      "code": "WEBHOOK_NOT_FOUND"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Campo inmutable o desconocido en el body (`VALIDATION_ERROR`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "VALIDATION_ERROR": {
                    "summary": "Validation failed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#VALIDATION_ERROR",
                      "title": "Validation failed",
                      "status": 422,
                      "detail": "One or more fields are invalid.",
                      "code": "VALIDATION_ERROR"
                    }
                  },
                  "WEBHOOK_URL_INVALID": {
                    "summary": "Webhook URL invalid",
                    "value": {
                      "type": "https://developers.allsign.io/errors#WEBHOOK_URL_INVALID",
                      "title": "Webhook URL invalid",
                      "status": 422,
                      "detail": "The webhook url must be an absolute https:// URL.",
                      "code": "WEBHOOK_URL_INVALID"
                    }
                  },
                  "UNKNOWN_EVENT_TYPE": {
                    "summary": "Unknown event type",
                    "value": {
                      "type": "https://developers.allsign.io/errors#UNKNOWN_EVENT_TYPE",
                      "title": "Unknown event type",
                      "status": 422,
                      "detail": "One or more event types are not in the v3 catalog.",
                      "code": "UNKNOWN_EVENT_TYPE"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Se superó el límite de tasa de tu API key; reintenta respetando `RateLimit-*` / `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          }
        },
        "description": "Merge-patch: solo cambian los campos que envías. Puedes reasignar `url`, `events`, `description`, o pausar/reactivar con `disabled`. Enviar un campo desconocido o inmutable es un **422 `VALIDATION_ERROR`**. Requiere `webhook:write`.",
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL",
            "source": "curl -X PATCH \"https://api.allsign.io/v3/webhooks/whe_7c9e6679742540de944be07fc1f90ae7\" \\\n  -H \"Authorization: Bearer allsign_live_sk_...\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{ \"events\": [\"document.completed\"], \"disabled\": false }'\n"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const id = 'whe_7c9e6679742540de944be07fc1f90ae7'\nconst res = await fetch(`https://api.allsign.io/v3/webhooks/${id}`, {\n  method: 'PATCH',\n  headers: {\n    Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ events: ['document.completed'] }),\n})\nconst endpoint = await res.json()\n"
          }
        ]
      },
      "delete": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Delete endpoint",
        "description": "Elimina un endpoint. Requiere el scope `webhook:delete`. Las entregas en vuelo hacia ese endpoint se marcan como fallidas (`webhook deleted`).",
        "operationId": "deleteWebhookEndpoint",
        "security": [
          {
            "Bearer Token": []
          }
        ],
        "parameters": [
          {
            "name": "webhook_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Webhook Id"
            },
            "description": "ID del endpoint (`whe_…`)."
          }
        ],
        "responses": {
          "204": {
            "description": "Eliminado. Sin body."
          },
          "400": {
            "description": "El identificador en un parámetro está mal formado (`INVALID_ID`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "INVALID_ID": {
                    "summary": "Malformed identifier",
                    "value": {
                      "type": "https://developers.allsign.io/errors#INVALID_ID",
                      "title": "Malformed identifier",
                      "status": 400,
                      "detail": "Invalid id; expected a typed, prefixed id (e.g. 'doc_…').",
                      "code": "INVALID_ID"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Falta el header `Authorization` o la API key no es válida.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "AUTHENTICATION_REQUIRED": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#AUTHENTICATION_REQUIRED",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "Provide an API key via Authorization: Bearer allsign_live_sk_….",
                      "code": "AUTHENTICATION_REQUIRED"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La API key no tiene el scope `webhook:delete`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "PERMISSION_DENIED": {
                    "summary": "Permission denied",
                    "value": {
                      "type": "https://developers.allsign.io/errors#PERMISSION_DENIED",
                      "title": "Permission denied",
                      "status": 403,
                      "detail": "This API key is missing the required scope.",
                      "code": "PERMISSION_DENIED",
                      "requiredScope": "document:write",
                      "yourScopes": [
                        "document:read"
                      ]
                    }
                  },
                  "IP_NOT_ALLOWED": {
                    "summary": "IP address not allowed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IP_NOT_ALLOWED",
                      "title": "IP address not allowed",
                      "status": 403,
                      "detail": "Access from this IP is not allowed for this API key.",
                      "code": "IP_NOT_ALLOWED"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No existe un endpoint con ese `id` en este tenant (`WEBHOOK_NOT_FOUND`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "WEBHOOK_NOT_FOUND": {
                    "summary": "Webhook endpoint not found",
                    "value": {
                      "type": "https://developers.allsign.io/errors#WEBHOOK_NOT_FOUND",
                      "title": "Webhook endpoint not found",
                      "status": 404,
                      "detail": "No webhook endpoint was found with that id.",
                      "code": "WEBHOOK_NOT_FOUND"
                    }
                  }
                },
                "example": {
                  "type": "about:blank",
                  "title": "Webhook not found",
                  "status": 404,
                  "code": "WEBHOOK_NOT_FOUND",
                  "detail": "No existe un endpoint con ese id en este tenant."
                }
              }
            }
          },
          "422": {
            "description": "El parámetro no pasa la validación (ej. `period` con un valor fuera del catálogo).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Se superó el límite de tasa de tu API key; reintenta respetando `RateLimit-*` / `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL",
            "source": "curl -X DELETE \"https://api.allsign.io/v3/webhooks/whe_7c9e6679742540de944be07fc1f90ae7\" \\\n  -H \"Authorization: Bearer allsign_live_sk_...\"\n"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const id = 'whe_7c9e6679742540de944be07fc1f90ae7'\nconst res = await fetch(`https://api.allsign.io/v3/webhooks/${id}`, {\n  method: 'DELETE',\n  headers: { Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}` },\n})\n// res.status === 204 en éxito\n"
          }
        ]
      }
    },
    "/webhooks/{webhook_id}/rotate-secret": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Rotate secret",
        "description": "Acuña un secreto `whsec_` nuevo. El anterior se conserva como *secreto previo* durante una **ventana de 24 h** en la que el despachador firma con **ambos** — así rotas sin downtime. Requiere `webhook:write` y honra `Idempotency-Key` (un reintento con la misma llave reproduce el mismo secreto en vez de rotar dos veces).",
        "operationId": "rotateWebhookSecret",
        "security": [
          {
            "Bearer Token": []
          }
        ],
        "parameters": [
          {
            "name": "webhook_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Webhook Id"
            },
            "description": "ID del endpoint (`whe_…`)."
          }
        ],
        "responses": {
          "200": {
            "description": "El endpoint con el nuevo `secret` en claro (única vez).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookEndpointCreatedResponse"
                },
                "example": {
                  "object": "webhook_endpoint",
                  "id": "whe_7c9e6679742540de944be07fc1f90ae7",
                  "secret": "whsec_1b2c3d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f607182",
                  "secretLast4": "7182",
                  "url": "https://tu-servidor.com/webhooks/allsign",
                  "events": [
                    "document.completed"
                  ],
                  "status": "enabled",
                  "apiVersion": "2026-07-11",
                  "environment": "live",
                  "livemode": true,
                  "createdAt": "2026-07-11T18:04:00Z"
                }
              }
            }
          },
          "400": {
            "description": "El identificador en un parámetro está mal formado (`INVALID_ID`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "INVALID_ID": {
                    "summary": "Malformed identifier",
                    "value": {
                      "type": "https://developers.allsign.io/errors#INVALID_ID",
                      "title": "Malformed identifier",
                      "status": 400,
                      "detail": "Invalid id; expected a typed, prefixed id (e.g. 'doc_…').",
                      "code": "INVALID_ID"
                    }
                  },
                  "IDEMPOTENCY_KEY_INVALID": {
                    "summary": "Idempotency key invalid",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IDEMPOTENCY_KEY_INVALID",
                      "title": "Idempotency key invalid",
                      "status": 400,
                      "detail": "Idempotency-Key must be a UUID v4.",
                      "code": "IDEMPOTENCY_KEY_INVALID"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Falta el header `Authorization` o la API key no es válida.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "AUTHENTICATION_REQUIRED": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#AUTHENTICATION_REQUIRED",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "Provide an API key via Authorization: Bearer allsign_live_sk_….",
                      "code": "AUTHENTICATION_REQUIRED"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La API key no tiene el scope `webhook:write`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "PERMISSION_DENIED": {
                    "summary": "Permission denied",
                    "value": {
                      "type": "https://developers.allsign.io/errors#PERMISSION_DENIED",
                      "title": "Permission denied",
                      "status": 403,
                      "detail": "This API key is missing the required scope.",
                      "code": "PERMISSION_DENIED",
                      "requiredScope": "document:write",
                      "yourScopes": [
                        "document:read"
                      ]
                    }
                  },
                  "IP_NOT_ALLOWED": {
                    "summary": "IP address not allowed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IP_NOT_ALLOWED",
                      "title": "IP address not allowed",
                      "status": 403,
                      "detail": "Access from this IP is not allowed for this API key.",
                      "code": "IP_NOT_ALLOWED"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No existe un endpoint con ese `id` en este tenant (`WEBHOOK_NOT_FOUND`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "WEBHOOK_NOT_FOUND": {
                    "summary": "Webhook endpoint not found",
                    "value": {
                      "type": "https://developers.allsign.io/errors#WEBHOOK_NOT_FOUND",
                      "title": "Webhook endpoint not found",
                      "status": 404,
                      "detail": "No webhook endpoint was found with that id.",
                      "code": "WEBHOOK_NOT_FOUND"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Reintento con la misma `Idempotency-Key` mientras la rotación original sigue en curso.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "IDEMPOTENCY_KEY_REUSED": {
                    "summary": "Idempotency key reused",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IDEMPOTENCY_KEY_REUSED",
                      "title": "Idempotency key reused",
                      "status": 409,
                      "detail": "This Idempotency-Key was already used with a different request.",
                      "code": "IDEMPOTENCY_KEY_REUSED"
                    }
                  },
                  "IDEMPOTENCY_KEY_IN_PROGRESS": {
                    "summary": "Idempotency key in progress",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IDEMPOTENCY_KEY_IN_PROGRESS",
                      "title": "Idempotency key in progress",
                      "status": 409,
                      "detail": "A request with this Idempotency-Key is still in progress.",
                      "code": "IDEMPOTENCY_KEY_IN_PROGRESS",
                      "retryAfter": 2
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "El parámetro no pasa la validación (ej. `period` con un valor fuera del catálogo).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Se superó el límite de tasa de tu API key; reintenta respetando `RateLimit-*` / `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL",
            "source": "curl -X POST \"https://api.allsign.io/v3/webhooks/whe_7c9e6679742540de944be07fc1f90ae7/rotate-secret\" \\\n  -H \"Authorization: Bearer allsign_live_sk_...\" \\\n  -H \"Idempotency-Key: 3fa85f64-5717-4562-b3fc-2c963f66afa6\"\n"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const id = 'whe_7c9e6679742540de944be07fc1f90ae7'\nconst res = await fetch(\n  `https://api.allsign.io/v3/webhooks/${id}/rotate-secret`,\n  {\n    method: 'POST',\n    headers: {\n      Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}`,\n      'Idempotency-Key': crypto.randomUUID(),\n    },\n  },\n)\nconst { secret } = await res.json()\n// Durante 24 h AllSign firma con el secreto nuevo Y el anterior\n"
          }
        ]
      }
    },
    "/webhooks/{webhook_id}/deliveries": {
      "get": {
        "tags": [
          "Webhooks"
        ],
        "summary": "List deliveries",
        "operationId": "listWebhookDeliveries",
        "security": [
          {
            "Bearer Token": []
          }
        ],
        "parameters": [
          {
            "name": "webhook_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Webhook Id"
            },
            "description": "ID del endpoint (`whe_…`)."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 100,
              "minimum": 1,
              "default": 20,
              "title": "Limit"
            },
            "description": "Resultados por página (1–100, default `20`)."
          },
          {
            "name": "startingAfter",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Startingafter"
            },
            "description": "Cursor: entregas después de este `id` (`whd_…`)."
          },
          {
            "name": "endingBefore",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Endingbefore"
            },
            "description": "Cursor: entregas antes de este `id` (`whd_…`)."
          }
        ],
        "responses": {
          "200": {
            "description": "Sobre de paginación por cursor con el log de entregas del endpoint.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookDeliveryList"
                },
                "example": {
                  "object": "list",
                  "data": [
                    {
                      "object": "webhook_delivery",
                      "id": "whd_a1b2c3d4e5f67890abcdef1234567890",
                      "status": "SENT",
                      "eventId": "evt_7c9e6679742540de944be07fc1f90ae7",
                      "eventType": "document.completed",
                      "targetUrl": "https://tu-servidor.com/webhooks/allsign",
                      "attempts": 1,
                      "lastStatusCode": 200,
                      "lastError": null,
                      "livemode": true,
                      "sentAt": "2026-07-11T19:03:01Z",
                      "createdAt": "2026-07-11T19:03:00Z",
                      "attemptHistory": [
                        {
                          "attemptNumber": 1,
                          "outcome": "SENT",
                          "statusCode": 200,
                          "responseBody": "{\"received\":true}",
                          "error": null,
                          "durationMs": 142,
                          "attemptedAt": "2026-07-11T19:03:01Z"
                        }
                      ]
                    }
                  ],
                  "hasMore": false,
                  "limit": 20,
                  "nextCursor": null,
                  "previousCursor": null
                }
              }
            }
          },
          "400": {
            "description": "El identificador en un parámetro está mal formado (`INVALID_ID`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "INVALID_ID": {
                    "summary": "Malformed identifier",
                    "value": {
                      "type": "https://developers.allsign.io/errors#INVALID_ID",
                      "title": "Malformed identifier",
                      "status": 400,
                      "detail": "Invalid id; expected a typed, prefixed id (e.g. 'doc_…').",
                      "code": "INVALID_ID"
                    }
                  },
                  "INVALID_CURSOR": {
                    "summary": "Invalid cursor",
                    "value": {
                      "type": "https://developers.allsign.io/errors#INVALID_CURSOR",
                      "title": "Invalid cursor",
                      "status": 400,
                      "detail": "The pagination cursor is malformed.",
                      "code": "INVALID_CURSOR"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Falta el header `Authorization` o la API key no es válida.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "AUTHENTICATION_REQUIRED": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#AUTHENTICATION_REQUIRED",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "Provide an API key via Authorization: Bearer allsign_live_sk_….",
                      "code": "AUTHENTICATION_REQUIRED"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La API key no tiene el scope `webhook:read`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "PERMISSION_DENIED": {
                    "summary": "Permission denied",
                    "value": {
                      "type": "https://developers.allsign.io/errors#PERMISSION_DENIED",
                      "title": "Permission denied",
                      "status": 403,
                      "detail": "This API key is missing the required scope.",
                      "code": "PERMISSION_DENIED",
                      "requiredScope": "document:write",
                      "yourScopes": [
                        "document:read"
                      ]
                    }
                  },
                  "IP_NOT_ALLOWED": {
                    "summary": "IP address not allowed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IP_NOT_ALLOWED",
                      "title": "IP address not allowed",
                      "status": 403,
                      "detail": "Access from this IP is not allowed for this API key.",
                      "code": "IP_NOT_ALLOWED"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No existe un endpoint con ese `id` en este tenant (`WEBHOOK_NOT_FOUND`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "WEBHOOK_NOT_FOUND": {
                    "summary": "Webhook endpoint not found",
                    "value": {
                      "type": "https://developers.allsign.io/errors#WEBHOOK_NOT_FOUND",
                      "title": "Webhook endpoint not found",
                      "status": 404,
                      "detail": "No webhook endpoint was found with that id.",
                      "code": "WEBHOOK_NOT_FOUND"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "El parámetro no pasa la validación (ej. `period` con un valor fuera del catálogo).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "VALIDATION_ERROR": {
                    "summary": "Validation failed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#VALIDATION_ERROR",
                      "title": "Validation failed",
                      "status": 422,
                      "detail": "One or more fields are invalid.",
                      "code": "VALIDATION_ERROR"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Se superó el límite de tasa de tu API key; reintenta respetando `RateLimit-*` / `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          }
        },
        "description": "El log de entregas de un endpoint — para depurar qué se envió, qué respondió tu servidor y cuántos intentos hubo. Pagina por cursor. Requiere `webhook:read`.",
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL",
            "source": "curl \"https://api.allsign.io/v3/webhooks/whe_7c9e6679742540de944be07fc1f90ae7/deliveries?limit=20\" \\\n  -H \"Authorization: Bearer allsign_live_sk_...\"\n"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const id = 'whe_7c9e6679742540de944be07fc1f90ae7'\nconst res = await fetch(\n  `https://api.allsign.io/v3/webhooks/${id}/deliveries?limit=20`,\n  { headers: { Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}` } },\n)\nconst { data: deliveries } = await res.json()\n"
          }
        ]
      }
    },
    "/users/me": {
      "get": {
        "tags": [
          "Users"
        ],
        "summary": "Get current user",
        "description": "Devuelve el tenant y el usuario detrás de tu credencial, junto con los scopes que tiene tu API key y el entorno en que opera. Usa este endpoint como sonda de salud de tu credencial antes de una integración. **Responde `200` (autenticado) o `401` (sin credencial válida) — nunca `403`.** Solo confirma tu propia identidad, así que no está protegido por ningún scope.",
        "operationId": "getCurrentUser",
        "responses": {
          "200": {
            "description": "El usuario y tenant detrás de la credencial, con sus scopes y entorno.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserMe"
                },
                "example": {
                  "id": "usr_1a2b3c4d5e6f7g8h",
                  "email": "tu@empresa.com",
                  "tenantId": "ten_9i8u7y6t5r4e3w2q",
                  "scopes": [
                    "document:read",
                    "document:write",
                    "analytics:read"
                  ],
                  "environment": "live",
                  "authMode": "api_key",
                  "livemode": true
                }
              }
            }
          },
          "401": {
            "description": "Falta el header `Authorization` o la API key no es válida.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "AUTHENTICATION_REQUIRED": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#AUTHENTICATION_REQUIRED",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "Provide an API key via Authorization: Bearer allsign_live_sk_….",
                      "code": "AUTHENTICATION_REQUIRED"
                    }
                  }
                },
                "example": {
                  "type": "https://developers.allsign.io/errors#AUTHENTICATION_REQUIRED",
                  "title": "Authentication required",
                  "status": 401,
                  "detail": "Falta el header Authorization o la credencial no es válida.",
                  "instance": "/v3/users/me",
                  "code": "AUTHENTICATION_REQUIRED",
                  "requestId": "req_9f86d081884c7d659a2feaa0c55ad015"
                }
              }
            }
          },
          "422": {
            "description": "El parámetro no pasa la validación (ej. `period` con un valor fuera del catálogo).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Se superó el límite de tasa de tu API key; reintenta respetando `RateLimit-*` / `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer Token": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL",
            "source": "curl \"https://api.allsign.io/v3/users/me\" \\\n  -H \"Authorization: Bearer allsign_live_sk_...\"\n"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const res = await fetch('https://api.allsign.io/v3/users/me', {\n  headers: { Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}` },\n})\nconst me = await res.json()\n\nif (!me.scopes.includes('document:write')) {\n  throw new Error('La API key no puede crear documentos')\n}\n"
          }
        ]
      }
    },
    "/users/team": {
      "get": {
        "tags": [
          "Users"
        ],
        "summary": "List team members",
        "description": "Lista a cada miembro de tu tenant con su rol. A diferencia de `/users/me`, este endpoint **sí está protegido por un scope**: expone datos de otras personas, así que requiere `user:read`.",
        "operationId": "listTeamMembers",
        "responses": {
          "200": {
            "description": "Colección acotada (`object: \"list\"`, `hasMore` siempre `false`) con los miembros del tenant.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TeamList"
                },
                "example": {
                  "object": "list",
                  "data": [
                    {
                      "id": "usr_1a2b3c4d5e6f7g8h",
                      "name": "Ana Ramírez",
                      "email": "ana@empresa.com",
                      "role": "owner"
                    },
                    {
                      "id": "usr_2b3c4d5e6f7g8h9i",
                      "name": "Luis Hernández",
                      "email": "luis@empresa.com",
                      "role": "member"
                    }
                  ],
                  "hasMore": false,
                  "nextCursor": null,
                  "previousCursor": null,
                  "limit": null
                }
              }
            }
          },
          "401": {
            "description": "Falta el header `Authorization` o la API key no es válida.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "AUTHENTICATION_REQUIRED": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#AUTHENTICATION_REQUIRED",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "Provide an API key via Authorization: Bearer allsign_live_sk_….",
                      "code": "AUTHENTICATION_REQUIRED"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La API key no tiene el scope `user:read`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "PERMISSION_DENIED": {
                    "summary": "Permission denied",
                    "value": {
                      "type": "https://developers.allsign.io/errors#PERMISSION_DENIED",
                      "title": "Permission denied",
                      "status": 403,
                      "detail": "This API key is missing the required scope.",
                      "code": "PERMISSION_DENIED",
                      "requiredScope": "document:write",
                      "yourScopes": [
                        "document:read"
                      ]
                    }
                  },
                  "IP_NOT_ALLOWED": {
                    "summary": "IP address not allowed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IP_NOT_ALLOWED",
                      "title": "IP address not allowed",
                      "status": 403,
                      "detail": "Access from this IP is not allowed for this API key.",
                      "code": "IP_NOT_ALLOWED"
                    }
                  }
                },
                "example": {
                  "type": "https://developers.allsign.io/errors#PERMISSION_DENIED",
                  "title": "Permission denied",
                  "status": 403,
                  "detail": "Your API key lacks the required scope for this operation.",
                  "instance": "/v3/users/team",
                  "code": "PERMISSION_DENIED",
                  "requestId": "req_a1b2c3d4e5f67890abcdef1234567890",
                  "requiredScope": "user:read"
                }
              }
            }
          },
          "422": {
            "description": "El parámetro no pasa la validación (ej. `period` con un valor fuera del catálogo).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Se superó el límite de tasa de tu API key; reintenta respetando `RateLimit-*` / `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer Token": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL",
            "source": "curl \"https://api.allsign.io/v3/users/team\" \\\n  -H \"Authorization: Bearer allsign_live_sk_...\"\n"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const res = await fetch('https://api.allsign.io/v3/users/team', {\n  headers: { Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}` },\n})\nconst { data: members } = await res.json()\n"
          }
        ]
      }
    },
    "/templates": {
      "get": {
        "tags": [
          "Templates"
        ],
        "summary": "List templates",
        "operationId": "listTemplates",
        "security": [
          {
            "Bearer Token": []
          }
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 100,
              "minimum": 1,
              "default": 20,
              "title": "Limit"
            },
            "description": "Resultados por página (1–100, default `20`)."
          },
          {
            "name": "startingAfter",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Startingafter"
            },
            "description": "Cursor: plantillas después de este `id` (`tmpl_…`)."
          },
          {
            "name": "endingBefore",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Endingbefore"
            },
            "description": "Cursor: plantillas antes de este `id` (`tmpl_…`)."
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/TemplateSort",
              "default": "-createdAt"
            },
            "description": "Orden por fecha de creación: `createdAt` o `-createdAt` (default `-createdAt`)."
          },
          {
            "name": "fileType",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Filetype"
            },
            "description": "Filtra por tipo de archivo (ej. `docx`, `pdf`)."
          },
          {
            "name": "category",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Category"
            },
            "description": "Filtra por categoría."
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 255
                },
                {
                  "type": "null"
                }
              ],
              "title": "Search"
            },
            "description": "Búsqueda por texto libre en el nombre (1–255 caracteres)."
          }
        ],
        "responses": {
          "200": {
            "description": "Sobre de paginación por cursor (`object: \"list\"`) con objetos Template.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TemplateList"
                },
                "example": {
                  "object": "list",
                  "data": [
                    {
                      "object": "template",
                      "id": "tmpl_7h6g5f4e3d2c1b0a",
                      "livemode": true,
                      "name": "Contrato de arrendamiento",
                      "description": "Plantilla estándar de arrendamiento",
                      "category": "inmobiliario",
                      "tags": [
                        "arrendamiento",
                        "renta"
                      ],
                      "fileType": "docx",
                      "variableCount": 6,
                      "usageCount": 34,
                      "currentVersion": 3,
                      "lastUsedAt": "2026-07-10T12:00:00Z",
                      "createdAt": "2026-05-02T09:00:00Z",
                      "updatedAt": "2026-07-01T14:30:00Z"
                    }
                  ],
                  "hasMore": true,
                  "limit": 20,
                  "nextCursor": "tmpl_7h6g5f4e3d2c1b0a",
                  "previousCursor": null
                }
              }
            }
          },
          "400": {
            "description": "El identificador en un parámetro está mal formado (`INVALID_ID`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "INVALID_CURSOR": {
                    "summary": "Invalid cursor",
                    "value": {
                      "type": "https://developers.allsign.io/errors#INVALID_CURSOR",
                      "title": "Invalid cursor",
                      "status": 400,
                      "detail": "The pagination cursor is malformed.",
                      "code": "INVALID_CURSOR"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Falta el header `Authorization` o la API key no es válida.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "AUTHENTICATION_REQUIRED": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#AUTHENTICATION_REQUIRED",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "Provide an API key via Authorization: Bearer allsign_live_sk_….",
                      "code": "AUTHENTICATION_REQUIRED"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La API key no tiene el scope requerido para plantillas.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "PERMISSION_DENIED": {
                    "summary": "Permission denied",
                    "value": {
                      "type": "https://developers.allsign.io/errors#PERMISSION_DENIED",
                      "title": "Permission denied",
                      "status": 403,
                      "detail": "This API key is missing the required scope.",
                      "code": "PERMISSION_DENIED",
                      "requiredScope": "document:write",
                      "yourScopes": [
                        "document:read"
                      ]
                    }
                  },
                  "IP_NOT_ALLOWED": {
                    "summary": "IP address not allowed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IP_NOT_ALLOWED",
                      "title": "IP address not allowed",
                      "status": 403,
                      "detail": "Access from this IP is not allowed for this API key.",
                      "code": "IP_NOT_ALLOWED"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "El parámetro no pasa la validación (ej. `period` con un valor fuera del catálogo).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "VALIDATION_ERROR": {
                    "summary": "Validation failed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#VALIDATION_ERROR",
                      "title": "Validation failed",
                      "status": 422,
                      "detail": "One or more fields are invalid.",
                      "code": "VALIDATION_ERROR"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Se superó el límite de tasa de tu API key; reintenta respetando `RateLimit-*` / `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          }
        },
        "description": "Lista tus plantillas con paginación por cursor y filtros por tipo de archivo, categoría y texto libre.",
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL",
            "source": "curl \"https://api.allsign.io/v3/templates?fileType=docx&limit=20\" \\\n  -H \"Authorization: Bearer allsign_live_sk_...\"\n"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const params = new URLSearchParams({ fileType: 'docx', limit: '20' })\nconst res = await fetch(`https://api.allsign.io/v3/templates?${params}`, {\n  headers: { Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}` },\n})\nconst { data, hasMore, nextCursor } = await res.json()\n"
          }
        ]
      }
    },
    "/templates/{template_id}": {
      "get": {
        "tags": [
          "Templates"
        ],
        "summary": "Retrieve template",
        "operationId": "getTemplate",
        "security": [
          {
            "Bearer Token": []
          }
        ],
        "parameters": [
          {
            "name": "template_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Template Id"
            },
            "description": "ID de la plantilla (`tmpl_…`)."
          }
        ],
        "responses": {
          "200": {
            "description": "El objeto Template.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Template"
                },
                "example": {
                  "object": "template",
                  "id": "tmpl_7h6g5f4e3d2c1b0a",
                  "livemode": true,
                  "name": "Contrato de arrendamiento",
                  "description": "Plantilla estándar de arrendamiento",
                  "category": "inmobiliario",
                  "tags": [
                    "arrendamiento",
                    "renta"
                  ],
                  "fileType": "docx",
                  "variableCount": 6,
                  "usageCount": 34,
                  "currentVersion": 3,
                  "lastUsedAt": "2026-07-10T12:00:00Z",
                  "createdAt": "2026-05-02T09:00:00Z",
                  "updatedAt": "2026-07-01T14:30:00Z"
                }
              }
            }
          },
          "400": {
            "description": "El identificador en un parámetro está mal formado (`INVALID_ID`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "INVALID_ID": {
                    "summary": "Malformed identifier",
                    "value": {
                      "type": "https://developers.allsign.io/errors#INVALID_ID",
                      "title": "Malformed identifier",
                      "status": 400,
                      "detail": "Invalid id; expected a typed, prefixed id (e.g. 'doc_…').",
                      "code": "INVALID_ID"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Falta el header `Authorization` o la API key no es válida.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "AUTHENTICATION_REQUIRED": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#AUTHENTICATION_REQUIRED",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "Provide an API key via Authorization: Bearer allsign_live_sk_….",
                      "code": "AUTHENTICATION_REQUIRED"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La API key no tiene el scope requerido para plantillas.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "PERMISSION_DENIED": {
                    "summary": "Permission denied",
                    "value": {
                      "type": "https://developers.allsign.io/errors#PERMISSION_DENIED",
                      "title": "Permission denied",
                      "status": 403,
                      "detail": "This API key is missing the required scope.",
                      "code": "PERMISSION_DENIED",
                      "requiredScope": "document:write",
                      "yourScopes": [
                        "document:read"
                      ]
                    }
                  },
                  "IP_NOT_ALLOWED": {
                    "summary": "IP address not allowed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IP_NOT_ALLOWED",
                      "title": "IP address not allowed",
                      "status": 403,
                      "detail": "Access from this IP is not allowed for this API key.",
                      "code": "IP_NOT_ALLOWED"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No existe una plantilla con ese `id` en este entorno (`TEMPLATE_NOT_FOUND`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "TEMPLATE_NOT_FOUND": {
                    "summary": "Template not found",
                    "value": {
                      "type": "https://developers.allsign.io/errors#TEMPLATE_NOT_FOUND",
                      "title": "Template not found",
                      "status": 404,
                      "detail": "No template was found with that id.",
                      "code": "TEMPLATE_NOT_FOUND"
                    }
                  }
                },
                "example": {
                  "type": "about:blank",
                  "title": "Template not found",
                  "status": 404,
                  "code": "TEMPLATE_NOT_FOUND",
                  "detail": "No existe una plantilla con ese id en este entorno."
                }
              }
            }
          },
          "422": {
            "description": "El parámetro no pasa la validación (ej. `period` con un valor fuera del catálogo).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Se superó el límite de tasa de tu API key; reintenta respetando `RateLimit-*` / `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          }
        },
        "description": "Consulta una plantilla por su `id`. Un `id` inexistente responde **404** (no 500).",
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL",
            "source": "curl \"https://api.allsign.io/v3/templates/tmpl_7h6g5f4e3d2c1b0a\" \\\n  -H \"Authorization: Bearer allsign_live_sk_...\"\n"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const id = 'tmpl_7h6g5f4e3d2c1b0a'\nconst res = await fetch(`https://api.allsign.io/v3/templates/${id}`, {\n  headers: { Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}` },\n})\nconst template = await res.json()\n"
          }
        ]
      }
    },
    "/templates/{template_id}/variables": {
      "get": {
        "tags": [
          "Templates"
        ],
        "summary": "List template variables",
        "operationId": "listTemplateVariables",
        "security": [
          {
            "Bearer Token": []
          }
        ],
        "parameters": [
          {
            "name": "template_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Template Id"
            },
            "description": "ID de la plantilla (`tmpl_…`)."
          }
        ],
        "responses": {
          "200": {
            "description": "Colección acotada (`object: \"list\"`, `hasMore` siempre `false`) con las variables de la plantilla.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TemplateVariableList"
                },
                "example": {
                  "object": "list",
                  "templateId": "tmpl_7h6g5f4e3d2c1b0a",
                  "data": [
                    {
                      "name": "nombre_completo",
                      "label": "Nombre completo",
                      "type": "text",
                      "required": true,
                      "defaultValue": null,
                      "options": null,
                      "role": null
                    },
                    {
                      "name": "monto",
                      "label": "Monto",
                      "type": "currency",
                      "required": true,
                      "defaultValue": null,
                      "options": null,
                      "role": null
                    },
                    {
                      "name": "arrendador__nombre",
                      "label": "Nombre del arrendador",
                      "type": "text",
                      "required": true,
                      "defaultValue": null,
                      "options": null,
                      "role": "Arrendador"
                    }
                  ],
                  "hasMore": false
                }
              }
            }
          },
          "400": {
            "description": "El identificador en un parámetro está mal formado (`INVALID_ID`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "INVALID_ID": {
                    "summary": "Malformed identifier",
                    "value": {
                      "type": "https://developers.allsign.io/errors#INVALID_ID",
                      "title": "Malformed identifier",
                      "status": 400,
                      "detail": "Invalid id; expected a typed, prefixed id (e.g. 'doc_…').",
                      "code": "INVALID_ID"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Falta el header `Authorization` o la API key no es válida.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "AUTHENTICATION_REQUIRED": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#AUTHENTICATION_REQUIRED",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "Provide an API key via Authorization: Bearer allsign_live_sk_….",
                      "code": "AUTHENTICATION_REQUIRED"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La API key no tiene el scope requerido para plantillas.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "PERMISSION_DENIED": {
                    "summary": "Permission denied",
                    "value": {
                      "type": "https://developers.allsign.io/errors#PERMISSION_DENIED",
                      "title": "Permission denied",
                      "status": 403,
                      "detail": "This API key is missing the required scope.",
                      "code": "PERMISSION_DENIED",
                      "requiredScope": "document:write",
                      "yourScopes": [
                        "document:read"
                      ]
                    }
                  },
                  "IP_NOT_ALLOWED": {
                    "summary": "IP address not allowed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IP_NOT_ALLOWED",
                      "title": "IP address not allowed",
                      "status": 403,
                      "detail": "Access from this IP is not allowed for this API key.",
                      "code": "IP_NOT_ALLOWED"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No existe una plantilla con ese `id` en este entorno (`TEMPLATE_NOT_FOUND`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "TEMPLATE_NOT_FOUND": {
                    "summary": "Template not found",
                    "value": {
                      "type": "https://developers.allsign.io/errors#TEMPLATE_NOT_FOUND",
                      "title": "Template not found",
                      "status": 404,
                      "detail": "No template was found with that id.",
                      "code": "TEMPLATE_NOT_FOUND"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "El parámetro no pasa la validación (ej. `period` con un valor fuera del catálogo).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Se superó el límite de tasa de tu API key; reintenta respetando `RateLimit-*` / `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          }
        },
        "description": "Lista las variables de una plantilla — justo lo que necesitas para armar el mapa `templateValues` de Create document. Es una colección acotada (no paginada por cursor): el número de variables lo limita el propio archivo.",
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL",
            "source": "curl \"https://api.allsign.io/v3/templates/tmpl_7h6g5f4e3d2c1b0a/variables\" \\\n  -H \"Authorization: Bearer allsign_live_sk_...\"\n"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const id = 'tmpl_7h6g5f4e3d2c1b0a'\nconst res = await fetch(\n  `https://api.allsign.io/v3/templates/${id}/variables`,\n  { headers: { Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}` } },\n)\nconst { data: variables } = await res.json()\n\n// Arma templateValues a partir de las variables requeridas\nconst templateValues = {\n  nombre_completo: 'Juan Pérez',\n  monto: '$150,000.00 MXN',\n}\n"
          }
        ]
      }
    },
    "/templates/{template_id}/validate-values": {
      "post": {
        "tags": [
          "Templates"
        ],
        "summary": "Validate template values",
        "description": "Comprueba un mapa `templateValues` contra las variables de la plantilla **sin crear nada y sin consumir crédito**. Es el ensayo previo de Create document: te dice qué falta antes de que el documento exista.\n\nPor qué importa: si envías `POST /v3/documents` sin una variable requerida, la respuesta es `422` y no se crea nada — pero ya escribiste el formulario, ya pediste los datos al usuario y ya armaste el request. Validar en cada guardado te deja corregir mientras el usuario sigue en la pantalla.\n\n**Siempre responde `200`**, incluso cuando el mapa está mal: es un diagnóstico, no un rechazo. Lo que te dice si puedes crear el documento es el campo `valid`.\n\nLa respuesta separa tres cosas que no pesan igual:\n\n- **`errors`** — falta una variable **requerida**. Es lo único que pone `valid` en `false`, y es exactamente lo que Create document rechaza con `422`.\n- **`warnings`** — el valor no cuadra con el `type` de la variable. **Nunca bloquean.** El `type` no se declara: se infiere del nombre, así que una variable llamada `forma_de_pago` se marca `currency` aunque contenga texto. Trátalos como una pista para revisar, no como un error.\n- **`ignored`** — llaves que enviaste y la plantilla no declara, casi siempre un typo (`nombre_completoo`). Create document las descarta en silencio, así que este es el único lugar donde te enteras.",
        "operationId": "validateTemplateValues",
        "security": [
          {
            "Bearer Token": []
          }
        ],
        "parameters": [
          {
            "name": "template_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Template Id"
            },
            "description": "ID de la plantilla (`tmpl_…`) contra la que se validan los valores."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TemplateValuesValidationRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "El diagnóstico del mapa (`object: \"template_values_validation\"`), con `valid` y los tres bloques. `200` no significa que el mapa esté bien — revisa `valid`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TemplateValuesValidation"
                }
              }
            }
          },
          "400": {
            "description": "El identificador en un parámetro está mal formado (`INVALID_ID`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "INVALID_ID": {
                    "summary": "Malformed identifier",
                    "value": {
                      "type": "https://developers.allsign.io/errors#INVALID_ID",
                      "title": "Malformed identifier",
                      "status": 400,
                      "detail": "Invalid id; expected a typed, prefixed id (e.g. 'doc_…').",
                      "code": "INVALID_ID"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Falta el header `Authorization` o la API key no es válida.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "AUTHENTICATION_REQUIRED": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#AUTHENTICATION_REQUIRED",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "Provide an API key via Authorization: Bearer allsign_live_sk_….",
                      "code": "AUTHENTICATION_REQUIRED"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La API key no tiene el scope requerido para plantillas.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "PERMISSION_DENIED": {
                    "summary": "Permission denied",
                    "value": {
                      "type": "https://developers.allsign.io/errors#PERMISSION_DENIED",
                      "title": "Permission denied",
                      "status": 403,
                      "detail": "This API key is missing the required scope.",
                      "code": "PERMISSION_DENIED",
                      "requiredScope": "document:write",
                      "yourScopes": [
                        "document:read"
                      ]
                    }
                  },
                  "IP_NOT_ALLOWED": {
                    "summary": "IP address not allowed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IP_NOT_ALLOWED",
                      "title": "IP address not allowed",
                      "status": 403,
                      "detail": "Access from this IP is not allowed for this API key.",
                      "code": "IP_NOT_ALLOWED"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No existe una plantilla con ese `id` en este entorno (`TEMPLATE_NOT_FOUND`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "TEMPLATE_NOT_FOUND": {
                    "summary": "Template not found",
                    "value": {
                      "type": "https://developers.allsign.io/errors#TEMPLATE_NOT_FOUND",
                      "title": "Template not found",
                      "status": 404,
                      "detail": "No template was found with that id.",
                      "code": "TEMPLATE_NOT_FOUND"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Se superó el límite de tasa de tu API key; reintenta respetando `RateLimit-*` / `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/folders": {
      "get": {
        "tags": [
          "Folders"
        ],
        "summary": "List folders",
        "operationId": "listFolders",
        "security": [
          {
            "Bearer Token": []
          }
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 100,
              "minimum": 1,
              "default": 20,
              "title": "Limit"
            },
            "description": "Resultados por página (1–100, default `20`)."
          },
          {
            "name": "startingAfter",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Startingafter"
            },
            "description": "Cursor: carpetas después de este `id` (`fld_…`)."
          },
          {
            "name": "endingBefore",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Endingbefore"
            },
            "description": "Cursor: carpetas antes de este `id` (`fld_…`)."
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/FolderSort",
              "default": "-createdAt"
            },
            "description": "Orden por fecha de creación: `createdAt` o `-createdAt` (default `-createdAt`)."
          }
        ],
        "responses": {
          "200": {
            "description": "Sobre de paginación por cursor (`object: \"list\"`) con objetos Folder.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FolderList"
                },
                "example": {
                  "object": "list",
                  "data": [
                    {
                      "object": "folder",
                      "id": "fld_c0ffeec0ffeec0ff",
                      "livemode": true,
                      "name": "Contratos 2026",
                      "parentId": null,
                      "ownerId": "usr_1a2b3c4d5e6f7g8h",
                      "hasDocs": true,
                      "isMain": false,
                      "createdAt": "2026-05-02T09:00:00Z",
                      "updatedAt": "2026-07-01T14:30:00Z"
                    }
                  ],
                  "hasMore": false,
                  "limit": 20,
                  "nextCursor": null,
                  "previousCursor": null
                }
              }
            }
          },
          "400": {
            "description": "El identificador en un parámetro está mal formado (`INVALID_ID`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "INVALID_CURSOR": {
                    "summary": "Invalid cursor",
                    "value": {
                      "type": "https://developers.allsign.io/errors#INVALID_CURSOR",
                      "title": "Invalid cursor",
                      "status": 400,
                      "detail": "The pagination cursor is malformed.",
                      "code": "INVALID_CURSOR"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Falta el header `Authorization` o la API key no es válida.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "AUTHENTICATION_REQUIRED": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#AUTHENTICATION_REQUIRED",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "Provide an API key via Authorization: Bearer allsign_live_sk_….",
                      "code": "AUTHENTICATION_REQUIRED"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La API key no tiene el scope requerido para carpetas.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "PERMISSION_DENIED": {
                    "summary": "Permission denied",
                    "value": {
                      "type": "https://developers.allsign.io/errors#PERMISSION_DENIED",
                      "title": "Permission denied",
                      "status": 403,
                      "detail": "This API key is missing the required scope.",
                      "code": "PERMISSION_DENIED",
                      "requiredScope": "document:write",
                      "yourScopes": [
                        "document:read"
                      ]
                    }
                  },
                  "IP_NOT_ALLOWED": {
                    "summary": "IP address not allowed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IP_NOT_ALLOWED",
                      "title": "IP address not allowed",
                      "status": 403,
                      "detail": "Access from this IP is not allowed for this API key.",
                      "code": "IP_NOT_ALLOWED"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "El parámetro no pasa la validación (ej. `period` con un valor fuera del catálogo).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "VALIDATION_ERROR": {
                    "summary": "Validation failed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#VALIDATION_ERROR",
                      "title": "Validation failed",
                      "status": 422,
                      "detail": "One or more fields are invalid.",
                      "code": "VALIDATION_ERROR"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Se superó el límite de tasa de tu API key; reintenta respetando `RateLimit-*` / `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          }
        },
        "description": "Lista tus carpetas con paginación por cursor.",
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL",
            "source": "curl \"https://api.allsign.io/v3/folders?limit=20\" \\\n  -H \"Authorization: Bearer allsign_live_sk_...\"\n"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const res = await fetch('https://api.allsign.io/v3/folders?limit=20', {\n  headers: { Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}` },\n})\nconst { data, hasMore, nextCursor } = await res.json()\n"
          }
        ]
      },
      "post": {
        "tags": [
          "Folders"
        ],
        "summary": "Create folder",
        "operationId": "createFolder",
        "security": [
          {
            "Bearer Token": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FolderCreateRequest"
              },
              "example": {
                "name": "Contratos 2026",
                "parentId": null
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "El objeto Folder creado.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Folder"
                },
                "example": {
                  "object": "folder",
                  "id": "fld_c0ffeec0ffeec0ff",
                  "livemode": true,
                  "name": "Contratos 2026",
                  "parentId": null,
                  "ownerId": "usr_1a2b3c4d5e6f7g8h",
                  "hasDocs": false,
                  "isMain": false,
                  "createdAt": "2026-07-12T15:00:00Z",
                  "updatedAt": "2026-07-12T15:00:00Z"
                }
              }
            }
          },
          "400": {
            "description": "El `parentId` está mal formado (`INVALID_ID`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "INVALID_ID": {
                    "summary": "Malformed identifier",
                    "value": {
                      "type": "https://developers.allsign.io/errors#INVALID_ID",
                      "title": "Malformed identifier",
                      "status": 400,
                      "detail": "Invalid id; expected a typed, prefixed id (e.g. 'doc_…').",
                      "code": "INVALID_ID"
                    }
                  }
                },
                "example": {
                  "type": "about:blank",
                  "title": "Invalid id",
                  "status": 400,
                  "code": "INVALID_ID",
                  "detail": "parentId debe ser un id con prefijo fld_."
                }
              }
            }
          },
          "401": {
            "description": "Falta el header `Authorization` o la API key no es válida.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "AUTHENTICATION_REQUIRED": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#AUTHENTICATION_REQUIRED",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "Provide an API key via Authorization: Bearer allsign_live_sk_….",
                      "code": "AUTHENTICATION_REQUIRED"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La API key no tiene el scope requerido para carpetas.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "PERMISSION_DENIED": {
                    "summary": "Permission denied",
                    "value": {
                      "type": "https://developers.allsign.io/errors#PERMISSION_DENIED",
                      "title": "Permission denied",
                      "status": 403,
                      "detail": "This API key is missing the required scope.",
                      "code": "PERMISSION_DENIED",
                      "requiredScope": "document:write",
                      "yourScopes": [
                        "document:read"
                      ]
                    }
                  },
                  "IP_NOT_ALLOWED": {
                    "summary": "IP address not allowed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IP_NOT_ALLOWED",
                      "title": "IP address not allowed",
                      "status": 403,
                      "detail": "Access from this IP is not allowed for this API key.",
                      "code": "IP_NOT_ALLOWED"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "El `parentId` no existe en este entorno.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "FOLDER_NOT_FOUND": {
                    "summary": "Folder not found",
                    "value": {
                      "type": "https://developers.allsign.io/errors#FOLDER_NOT_FOUND",
                      "title": "Folder not found",
                      "status": 404,
                      "detail": "No folder was found with that id.",
                      "code": "FOLDER_NOT_FOUND"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "El parámetro no pasa la validación (ej. `period` con un valor fuera del catálogo).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "VALIDATION_ERROR": {
                    "summary": "Validation failed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#VALIDATION_ERROR",
                      "title": "Validation failed",
                      "status": 422,
                      "detail": "One or more fields are invalid.",
                      "code": "VALIDATION_ERROR"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Se superó el límite de tasa de tu API key; reintenta respetando `RateLimit-*` / `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          }
        },
        "description": "Crea una carpeta. Puedes anidarla pasando un `parentId`; si lo omites (o mandas `null`), la carpeta queda a nivel raíz.",
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL",
            "source": "curl \"https://api.allsign.io/v3/folders\" \\\n  -H \"Authorization: Bearer allsign_live_sk_...\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{ \"name\": \"Contratos 2026\", \"parentId\": null }'\n"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const res = await fetch('https://api.allsign.io/v3/folders', {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ name: 'Contratos 2026', parentId: null }),\n})\nconst folder = await res.json()\n"
          }
        ]
      }
    },
    "/folders/{folder_id}": {
      "get": {
        "tags": [
          "Folders"
        ],
        "summary": "Retrieve folder",
        "operationId": "getFolder",
        "security": [
          {
            "Bearer Token": []
          }
        ],
        "parameters": [
          {
            "name": "folder_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Folder Id"
            },
            "description": "ID de la carpeta (`fld_…`)."
          }
        ],
        "responses": {
          "200": {
            "description": "El objeto Folder.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Folder"
                },
                "example": {
                  "object": "folder",
                  "id": "fld_c0ffeec0ffeec0ff",
                  "livemode": true,
                  "name": "Contratos 2026",
                  "parentId": null,
                  "ownerId": "usr_1a2b3c4d5e6f7g8h",
                  "hasDocs": true,
                  "isMain": false,
                  "createdAt": "2026-05-02T09:00:00Z",
                  "updatedAt": "2026-07-01T14:30:00Z"
                }
              }
            }
          },
          "400": {
            "description": "El identificador en un parámetro está mal formado (`INVALID_ID`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "INVALID_ID": {
                    "summary": "Malformed identifier",
                    "value": {
                      "type": "https://developers.allsign.io/errors#INVALID_ID",
                      "title": "Malformed identifier",
                      "status": 400,
                      "detail": "Invalid id; expected a typed, prefixed id (e.g. 'doc_…').",
                      "code": "INVALID_ID"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Falta el header `Authorization` o la API key no es válida.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "AUTHENTICATION_REQUIRED": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#AUTHENTICATION_REQUIRED",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "Provide an API key via Authorization: Bearer allsign_live_sk_….",
                      "code": "AUTHENTICATION_REQUIRED"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La API key no tiene el scope requerido para carpetas.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "PERMISSION_DENIED": {
                    "summary": "Permission denied",
                    "value": {
                      "type": "https://developers.allsign.io/errors#PERMISSION_DENIED",
                      "title": "Permission denied",
                      "status": 403,
                      "detail": "This API key is missing the required scope.",
                      "code": "PERMISSION_DENIED",
                      "requiredScope": "document:write",
                      "yourScopes": [
                        "document:read"
                      ]
                    }
                  },
                  "IP_NOT_ALLOWED": {
                    "summary": "IP address not allowed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IP_NOT_ALLOWED",
                      "title": "IP address not allowed",
                      "status": 403,
                      "detail": "Access from this IP is not allowed for this API key.",
                      "code": "IP_NOT_ALLOWED"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No existe una carpeta con ese `id` en este entorno (`FOLDER_NOT_FOUND`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "FOLDER_NOT_FOUND": {
                    "summary": "Folder not found",
                    "value": {
                      "type": "https://developers.allsign.io/errors#FOLDER_NOT_FOUND",
                      "title": "Folder not found",
                      "status": 404,
                      "detail": "No folder was found with that id.",
                      "code": "FOLDER_NOT_FOUND"
                    }
                  }
                },
                "example": {
                  "type": "about:blank",
                  "title": "Folder not found",
                  "status": 404,
                  "code": "FOLDER_NOT_FOUND",
                  "detail": "No existe una carpeta con ese id en este entorno."
                }
              }
            }
          },
          "422": {
            "description": "El parámetro no pasa la validación (ej. `period` con un valor fuera del catálogo).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Se superó el límite de tasa de tu API key; reintenta respetando `RateLimit-*` / `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          }
        },
        "description": "Consulta una carpeta por su `id`.",
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL",
            "source": "curl \"https://api.allsign.io/v3/folders/fld_c0ffeec0ffeec0ff\" \\\n  -H \"Authorization: Bearer allsign_live_sk_...\"\n"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const id = 'fld_c0ffeec0ffeec0ff'\nconst res = await fetch(`https://api.allsign.io/v3/folders/${id}`, {\n  headers: { Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}` },\n})\nconst folder = await res.json()\n"
          }
        ]
      },
      "patch": {
        "tags": [
          "Folders"
        ],
        "summary": "Update folder",
        "description": "Merge-patch parcial: solo se modifican los campos que envías. Los únicos campos mutables son `name` y `parentId`. Enviar cualquier otro campo se rechaza al parsear con **422 `VALIDATION_ERROR`** nombrando el campo ofensor.",
        "operationId": "updateFolder",
        "security": [
          {
            "Bearer Token": []
          }
        ],
        "parameters": [
          {
            "name": "folder_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Folder Id"
            },
            "description": "ID de la carpeta (`fld_…`)."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FolderUpdateRequest"
              },
              "example": {
                "name": "Contratos firmados 2026"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "El objeto Folder actualizado.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Folder"
                },
                "example": {
                  "object": "folder",
                  "id": "fld_c0ffeec0ffeec0ff",
                  "livemode": true,
                  "name": "Contratos firmados 2026",
                  "parentId": null,
                  "ownerId": "usr_1a2b3c4d5e6f7g8h",
                  "hasDocs": true,
                  "isMain": false,
                  "createdAt": "2026-05-02T09:00:00Z",
                  "updatedAt": "2026-07-12T16:40:00Z"
                }
              }
            }
          },
          "400": {
            "description": "El identificador en un parámetro está mal formado (`INVALID_ID`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "INVALID_ID": {
                    "summary": "Malformed identifier",
                    "value": {
                      "type": "https://developers.allsign.io/errors#INVALID_ID",
                      "title": "Malformed identifier",
                      "status": 400,
                      "detail": "Invalid id; expected a typed, prefixed id (e.g. 'doc_…').",
                      "code": "INVALID_ID"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Falta el header `Authorization` o la API key no es válida.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "AUTHENTICATION_REQUIRED": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#AUTHENTICATION_REQUIRED",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "Provide an API key via Authorization: Bearer allsign_live_sk_….",
                      "code": "AUTHENTICATION_REQUIRED"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La API key no tiene el scope requerido para carpetas.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "PERMISSION_DENIED": {
                    "summary": "Permission denied",
                    "value": {
                      "type": "https://developers.allsign.io/errors#PERMISSION_DENIED",
                      "title": "Permission denied",
                      "status": 403,
                      "detail": "This API key is missing the required scope.",
                      "code": "PERMISSION_DENIED",
                      "requiredScope": "document:write",
                      "yourScopes": [
                        "document:read"
                      ]
                    }
                  },
                  "IP_NOT_ALLOWED": {
                    "summary": "IP address not allowed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IP_NOT_ALLOWED",
                      "title": "IP address not allowed",
                      "status": 403,
                      "detail": "Access from this IP is not allowed for this API key.",
                      "code": "IP_NOT_ALLOWED"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No existe una carpeta con ese `id` en este entorno (`FOLDER_NOT_FOUND`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "FOLDER_NOT_FOUND": {
                    "summary": "Folder not found",
                    "value": {
                      "type": "https://developers.allsign.io/errors#FOLDER_NOT_FOUND",
                      "title": "Folder not found",
                      "status": 404,
                      "detail": "No folder was found with that id.",
                      "code": "FOLDER_NOT_FOUND"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Campo inmutable o desconocido en el body (`VALIDATION_ERROR`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "VALIDATION_ERROR": {
                    "summary": "Validation failed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#VALIDATION_ERROR",
                      "title": "Validation failed",
                      "status": 422,
                      "detail": "One or more fields are invalid.",
                      "code": "VALIDATION_ERROR"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Se superó el límite de tasa de tu API key; reintenta respetando `RateLimit-*` / `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL",
            "source": "curl -X PATCH \"https://api.allsign.io/v3/folders/fld_c0ffeec0ffeec0ff\" \\\n  -H \"Authorization: Bearer allsign_live_sk_...\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{ \"name\": \"Contratos firmados 2026\" }'\n"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const id = 'fld_c0ffeec0ffeec0ff'\nconst res = await fetch(`https://api.allsign.io/v3/folders/${id}`, {\n  method: 'PATCH',\n  headers: {\n    Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}`,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ name: 'Contratos firmados 2026' }),\n})\nconst folder = await res.json()\n"
          }
        ]
      },
      "delete": {
        "tags": [
          "Folders"
        ],
        "summary": "Delete folder",
        "description": "Elimina una carpeta **vacía**. Si la carpeta todavía tiene documentos o subcarpetas, la operación falla con **400** (mismos guardarraíles que protegen tu jerarquía). Vacía o mueve su contenido primero. A diferencia de `FOLDER_NOT_FOUND`, el caso \"carpeta no vacía\" todavía usa el formato de error heredado y aún no forma parte del catálogo problem+json congelado.",
        "operationId": "deleteFolder",
        "security": [
          {
            "Bearer Token": []
          }
        ],
        "parameters": [
          {
            "name": "folder_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Folder Id"
            },
            "description": "ID de la carpeta (`fld_…`)."
          }
        ],
        "responses": {
          "204": {
            "description": "Eliminada. Sin body."
          },
          "400": {
            "description": "La carpeta no está vacía (aún tiene documentos o subcarpetas) — formato de error heredado, sin `code` estable.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "INVALID_ID": {
                    "summary": "Malformed identifier",
                    "value": {
                      "type": "https://developers.allsign.io/errors#INVALID_ID",
                      "title": "Malformed identifier",
                      "status": 400,
                      "detail": "Invalid id; expected a typed, prefixed id (e.g. 'doc_…').",
                      "code": "INVALID_ID"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Falta el header `Authorization` o la API key no es válida.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "AUTHENTICATION_REQUIRED": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#AUTHENTICATION_REQUIRED",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "Provide an API key via Authorization: Bearer allsign_live_sk_….",
                      "code": "AUTHENTICATION_REQUIRED"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La API key no tiene el scope requerido para carpetas.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "PERMISSION_DENIED": {
                    "summary": "Permission denied",
                    "value": {
                      "type": "https://developers.allsign.io/errors#PERMISSION_DENIED",
                      "title": "Permission denied",
                      "status": 403,
                      "detail": "This API key is missing the required scope.",
                      "code": "PERMISSION_DENIED",
                      "requiredScope": "document:write",
                      "yourScopes": [
                        "document:read"
                      ]
                    }
                  },
                  "IP_NOT_ALLOWED": {
                    "summary": "IP address not allowed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IP_NOT_ALLOWED",
                      "title": "IP address not allowed",
                      "status": 403,
                      "detail": "Access from this IP is not allowed for this API key.",
                      "code": "IP_NOT_ALLOWED"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No existe una carpeta con ese `id` en este entorno (`FOLDER_NOT_FOUND`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "FOLDER_NOT_FOUND": {
                    "summary": "Folder not found",
                    "value": {
                      "type": "https://developers.allsign.io/errors#FOLDER_NOT_FOUND",
                      "title": "Folder not found",
                      "status": 404,
                      "detail": "No folder was found with that id.",
                      "code": "FOLDER_NOT_FOUND"
                    }
                  }
                },
                "example": {
                  "type": "about:blank",
                  "title": "Folder not found",
                  "status": 404,
                  "code": "FOLDER_NOT_FOUND",
                  "detail": "No existe una carpeta con ese id en este entorno."
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "FOLDER_NOT_EMPTY": {
                    "summary": "Conflict",
                    "value": {
                      "type": "https://developers.allsign.io/errors#FOLDER_NOT_EMPTY",
                      "title": "Conflict",
                      "status": 409,
                      "detail": "Move or delete the folder's documents and subfolders first.",
                      "code": "FOLDER_NOT_EMPTY"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "El parámetro no pasa la validación (ej. `period` con un valor fuera del catálogo).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Se superó el límite de tasa de tu API key; reintenta respetando `RateLimit-*` / `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL",
            "source": "curl -X DELETE \"https://api.allsign.io/v3/folders/fld_c0ffeec0ffeec0ff\" \\\n  -H \"Authorization: Bearer allsign_live_sk_...\"\n"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const id = 'fld_c0ffeec0ffeec0ff'\nconst res = await fetch(`https://api.allsign.io/v3/folders/${id}`, {\n  method: 'DELETE',\n  headers: { Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}` },\n})\n// res.status === 204 en éxito\n"
          }
        ]
      }
    },
    "/folders/{folder_id}/documents": {
      "get": {
        "tags": [
          "Folders"
        ],
        "summary": "List folder documents",
        "operationId": "listFolderDocuments",
        "security": [
          {
            "Bearer Token": []
          }
        ],
        "parameters": [
          {
            "name": "folder_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Folder Id"
            },
            "description": "ID de la carpeta (`fld_…`)."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 100,
              "minimum": 1,
              "default": 20,
              "title": "Limit"
            },
            "description": "Resultados por página (1–100, default `20`)."
          },
          {
            "name": "startingAfter",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Startingafter"
            },
            "description": "Cursor: documentos después de este `id` (`doc_…`)."
          },
          {
            "name": "endingBefore",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Endingbefore"
            },
            "description": "Cursor: documentos antes de este `id` (`doc_…`)."
          }
        ],
        "responses": {
          "200": {
            "description": "Sobre de paginación por cursor con objetos Document.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentList"
                },
                "example": {
                  "object": "list",
                  "data": [
                    {
                      "object": "document",
                      "id": "doc_5Qr9tA3fZwLZmp3D1bCdEfG",
                      "livemode": true,
                      "name": "Contrato de arrendamiento 2026.pdf",
                      "status": "completed",
                      "documentType": "editable",
                      "signerCount": 2,
                      "signedCount": 2,
                      "ownerId": "usr_1a2b3c4d5e6f7g8h",
                      "orgId": "org_9i8u7y6t5r4e3w2q",
                      "folderId": "fld_c0ffeec0ffeec0ff",
                      "expiresAt": null,
                      "expirationReminders": null,
                      "createdAt": "2026-07-11T18:04:00Z",
                      "updatedAt": "2026-07-11T22:00:00Z"
                    }
                  ],
                  "hasMore": false,
                  "limit": 20,
                  "nextCursor": null,
                  "previousCursor": null
                }
              }
            }
          },
          "400": {
            "description": "El identificador en un parámetro está mal formado (`INVALID_ID`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "INVALID_ID": {
                    "summary": "Malformed identifier",
                    "value": {
                      "type": "https://developers.allsign.io/errors#INVALID_ID",
                      "title": "Malformed identifier",
                      "status": 400,
                      "detail": "Invalid id; expected a typed, prefixed id (e.g. 'doc_…').",
                      "code": "INVALID_ID"
                    }
                  },
                  "INVALID_CURSOR": {
                    "summary": "Invalid cursor",
                    "value": {
                      "type": "https://developers.allsign.io/errors#INVALID_CURSOR",
                      "title": "Invalid cursor",
                      "status": 400,
                      "detail": "The pagination cursor is malformed.",
                      "code": "INVALID_CURSOR"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Falta el header `Authorization` o la API key no es válida.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "AUTHENTICATION_REQUIRED": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#AUTHENTICATION_REQUIRED",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "Provide an API key via Authorization: Bearer allsign_live_sk_….",
                      "code": "AUTHENTICATION_REQUIRED"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La API key no tiene el scope requerido para carpetas.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "PERMISSION_DENIED": {
                    "summary": "Permission denied",
                    "value": {
                      "type": "https://developers.allsign.io/errors#PERMISSION_DENIED",
                      "title": "Permission denied",
                      "status": 403,
                      "detail": "This API key is missing the required scope.",
                      "code": "PERMISSION_DENIED",
                      "requiredScope": "document:write",
                      "yourScopes": [
                        "document:read"
                      ]
                    }
                  },
                  "IP_NOT_ALLOWED": {
                    "summary": "IP address not allowed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IP_NOT_ALLOWED",
                      "title": "IP address not allowed",
                      "status": 403,
                      "detail": "Access from this IP is not allowed for this API key.",
                      "code": "IP_NOT_ALLOWED"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No existe una carpeta con ese `id` en este entorno (`FOLDER_NOT_FOUND`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "FOLDER_NOT_FOUND": {
                    "summary": "Folder not found",
                    "value": {
                      "type": "https://developers.allsign.io/errors#FOLDER_NOT_FOUND",
                      "title": "Folder not found",
                      "status": 404,
                      "detail": "No folder was found with that id.",
                      "code": "FOLDER_NOT_FOUND"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "El parámetro no pasa la validación (ej. `period` con un valor fuera del catálogo).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "VALIDATION_ERROR": {
                    "summary": "Validation failed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#VALIDATION_ERROR",
                      "title": "Validation failed",
                      "status": 422,
                      "detail": "One or more fields are invalid.",
                      "code": "VALIDATION_ERROR"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Se superó el límite de tasa de tu API key; reintenta respetando `RateLimit-*` / `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          }
        },
        "description": "Lista los documentos contenidos en una carpeta, con paginación por cursor. Devuelve el mismo sobre que List documents.",
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL",
            "source": "curl \"https://api.allsign.io/v3/folders/fld_c0ffeec0ffeec0ff/documents?limit=20\" \\\n  -H \"Authorization: Bearer allsign_live_sk_...\"\n"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const id = 'fld_c0ffeec0ffeec0ff'\nconst res = await fetch(\n  `https://api.allsign.io/v3/folders/${id}/documents?limit=20`,\n  { headers: { Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}` } },\n)\nconst { data, hasMore, nextCursor } = await res.json()\n"
          }
        ]
      }
    },
    "/analytics/kpis": {
      "get": {
        "tags": [
          "Analytics"
        ],
        "summary": "KPIs",
        "operationId": "analyticsKpis",
        "security": [
          {
            "Bearer Token": []
          }
        ],
        "parameters": [
          {
            "name": "period",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "pattern": "^(7d|30d|90d|12m)$",
              "description": "Time period",
              "default": "30d",
              "title": "Period"
            },
            "description": "Ventana de tiempo: `7d`, `30d`, `90d` o `12m`. Default `30d`. Otro valor es un `422 VALIDATION_ERROR`."
          }
        ],
        "responses": {
          "200": {
            "description": "Objeto plano con los KPIs del periodo.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AnalyticsKPIs"
                },
                "example": {
                  "totalDocs": 150,
                  "completed": 42,
                  "pending": 93,
                  "expired": 15,
                  "completionRate": 0.28,
                  "avgSignTimeHours": 18.4
                }
              }
            }
          },
          "401": {
            "description": "Falta el header `Authorization` o la API key no es válida.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "AUTHENTICATION_REQUIRED": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#AUTHENTICATION_REQUIRED",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "Provide an API key via Authorization: Bearer allsign_live_sk_….",
                      "code": "AUTHENTICATION_REQUIRED"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La API key no tiene el scope `analytics:read` (o `analytics:*`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "PERMISSION_DENIED": {
                    "summary": "Permission denied",
                    "value": {
                      "type": "https://developers.allsign.io/errors#PERMISSION_DENIED",
                      "title": "Permission denied",
                      "status": 403,
                      "detail": "This API key is missing the required scope.",
                      "code": "PERMISSION_DENIED",
                      "requiredScope": "document:write",
                      "yourScopes": [
                        "document:read"
                      ]
                    }
                  },
                  "IP_NOT_ALLOWED": {
                    "summary": "IP address not allowed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IP_NOT_ALLOWED",
                      "title": "IP address not allowed",
                      "status": 403,
                      "detail": "Access from this IP is not allowed for this API key.",
                      "code": "IP_NOT_ALLOWED"
                    }
                  }
                },
                "example": {
                  "type": "https://developers.allsign.io/errors#PERMISSION_DENIED",
                  "title": "Permission denied",
                  "status": 403,
                  "detail": "Your API key lacks the required scope for this operation.",
                  "instance": "/v3/analytics/kpis",
                  "code": "PERMISSION_DENIED",
                  "requestId": "req_9f86d081884c7d659a2feaa0c55ad015",
                  "requiredScope": "analytics:read"
                }
              }
            }
          },
          "422": {
            "description": "El parámetro no pasa la validación (ej. `period` con un valor fuera del catálogo).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "VALIDATION_ERROR": {
                    "summary": "Validation failed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#VALIDATION_ERROR",
                      "title": "Validation failed",
                      "status": 422,
                      "detail": "One or more fields are invalid.",
                      "code": "VALIDATION_ERROR"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Se superó el límite de tasa de tu API key; reintenta respetando `RateLimit-*` / `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          }
        },
        "description": "Indicadores clave del periodo: total de documentos, completados, pendientes, expirados, tasa de finalización y tiempo promedio de firma. La respuesta es un **objeto plano** (no un sobre `list`).",
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL",
            "source": "curl \"https://api.allsign.io/v3/analytics/kpis?period=30d\" \\\n  -H \"Authorization: Bearer allsign_live_sk_...\"\n"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const res = await fetch(\n  'https://api.allsign.io/v3/analytics/kpis?period=30d',\n  { headers: { Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}` } },\n)\nconst kpis = await res.json()\n"
          }
        ]
      }
    },
    "/analytics/funnel": {
      "get": {
        "tags": [
          "Analytics"
        ],
        "summary": "Signing funnel",
        "operationId": "analyticsFunnel",
        "security": [
          {
            "Bearer Token": []
          }
        ],
        "parameters": [
          {
            "name": "period",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "pattern": "^(7d|30d|90d|12m)$",
              "description": "Time period",
              "default": "30d",
              "title": "Period"
            },
            "description": "Ventana de tiempo: `7d`, `30d`, `90d` o `12m`. Default `30d`."
          }
        ],
        "responses": {
          "200": {
            "description": "Colección acotada (`object: \"list\"`) con las 4 etapas del embudo, en orden.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FunnelList"
                },
                "example": {
                  "object": "list",
                  "data": [
                    {
                      "label": "Enviados",
                      "count": 150,
                      "pct": 100
                    },
                    {
                      "label": "En progreso",
                      "count": 93,
                      "pct": 62
                    },
                    {
                      "label": "Completados",
                      "count": 42,
                      "pct": 28
                    },
                    {
                      "label": "Expirados",
                      "count": 15,
                      "pct": 10
                    }
                  ],
                  "hasMore": false
                }
              }
            }
          },
          "401": {
            "description": "Falta el header `Authorization` o la API key no es válida.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "AUTHENTICATION_REQUIRED": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#AUTHENTICATION_REQUIRED",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "Provide an API key via Authorization: Bearer allsign_live_sk_….",
                      "code": "AUTHENTICATION_REQUIRED"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La API key no tiene el scope `analytics:read` (o `analytics:*`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "PERMISSION_DENIED": {
                    "summary": "Permission denied",
                    "value": {
                      "type": "https://developers.allsign.io/errors#PERMISSION_DENIED",
                      "title": "Permission denied",
                      "status": 403,
                      "detail": "This API key is missing the required scope.",
                      "code": "PERMISSION_DENIED",
                      "requiredScope": "document:write",
                      "yourScopes": [
                        "document:read"
                      ]
                    }
                  },
                  "IP_NOT_ALLOWED": {
                    "summary": "IP address not allowed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IP_NOT_ALLOWED",
                      "title": "IP address not allowed",
                      "status": 403,
                      "detail": "Access from this IP is not allowed for this API key.",
                      "code": "IP_NOT_ALLOWED"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "El parámetro no pasa la validación (ej. `period` con un valor fuera del catálogo).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "VALIDATION_ERROR": {
                    "summary": "Validation failed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#VALIDATION_ERROR",
                      "title": "Validation failed",
                      "status": 422,
                      "detail": "One or more fields are invalid.",
                      "code": "VALIDATION_ERROR"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Se superó el límite de tasa de tu API key; reintenta respetando `RateLimit-*` / `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          }
        },
        "description": "El embudo de firma en **cuatro etapas fijas**: Enviados → En progreso → Completados → Expirados. La colección siempre trae exactamente 4 elementos.",
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL",
            "source": "curl \"https://api.allsign.io/v3/analytics/funnel?period=30d\" \\\n  -H \"Authorization: Bearer allsign_live_sk_...\"\n"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const res = await fetch(\n  'https://api.allsign.io/v3/analytics/funnel?period=30d',\n  { headers: { Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}` } },\n)\nconst { data: stages } = await res.json()\n"
          }
        ]
      }
    },
    "/analytics/trend": {
      "get": {
        "tags": [
          "Analytics"
        ],
        "summary": "Monthly trend",
        "operationId": "analyticsTrend",
        "responses": {
          "200": {
            "description": "Colección acotada (`object: \"list\"`) con un punto por mes (hasta 6).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrendList"
                },
                "example": {
                  "object": "list",
                  "data": [
                    {
                      "month": "2026-02",
                      "signed": 28,
                      "avgHours": 22.1
                    },
                    {
                      "month": "2026-03",
                      "signed": 35,
                      "avgHours": 19.8
                    },
                    {
                      "month": "2026-07",
                      "signed": 42,
                      "avgHours": 18.4
                    }
                  ],
                  "hasMore": false
                }
              }
            }
          },
          "401": {
            "description": "Falta el header `Authorization` o la API key no es válida.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "AUTHENTICATION_REQUIRED": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#AUTHENTICATION_REQUIRED",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "Provide an API key via Authorization: Bearer allsign_live_sk_….",
                      "code": "AUTHENTICATION_REQUIRED"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La API key no tiene el scope `analytics:read` (o `analytics:*`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "PERMISSION_DENIED": {
                    "summary": "Permission denied",
                    "value": {
                      "type": "https://developers.allsign.io/errors#PERMISSION_DENIED",
                      "title": "Permission denied",
                      "status": 403,
                      "detail": "This API key is missing the required scope.",
                      "code": "PERMISSION_DENIED",
                      "requiredScope": "document:write",
                      "yourScopes": [
                        "document:read"
                      ]
                    }
                  },
                  "IP_NOT_ALLOWED": {
                    "summary": "IP address not allowed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IP_NOT_ALLOWED",
                      "title": "IP address not allowed",
                      "status": 403,
                      "detail": "Access from this IP is not allowed for this API key.",
                      "code": "IP_NOT_ALLOWED"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "El parámetro no pasa la validación (ej. `period` con un valor fuera del catálogo).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Se superó el límite de tasa de tu API key; reintenta respetando `RateLimit-*` / `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer Token": []
          }
        ],
        "description": "Documentos firmados y horas promedio de firma por mes, para los **últimos 6 meses** (fijo, sin parámetros).",
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL",
            "source": "curl \"https://api.allsign.io/v3/analytics/trend\" \\\n  -H \"Authorization: Bearer allsign_live_sk_...\"\n"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const res = await fetch('https://api.allsign.io/v3/analytics/trend', {\n  headers: { Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}` },\n})\nconst { data: months } = await res.json()\n"
          }
        ]
      }
    },
    "/analytics/bottlenecks": {
      "get": {
        "tags": [
          "Analytics"
        ],
        "summary": "Bottlenecks",
        "operationId": "analyticsBottlenecks",
        "security": [
          {
            "Bearer Token": []
          }
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 20,
              "minimum": 1,
              "description": "Max bottleneck entries",
              "default": 5,
              "title": "Limit"
            },
            "description": "Máximo de firmantes a devolver (1–20, default `5`)."
          }
        ],
        "responses": {
          "200": {
            "description": "Colección acotada (`object: \"list\"`), firmantes ordenados por firmas pendientes.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BottleneckList"
                },
                "example": {
                  "object": "list",
                  "data": [
                    {
                      "signerName": "María López",
                      "signerEmail": "maria@empresa.com",
                      "pendingCount": 7,
                      "avgDays": 4.2
                    },
                    {
                      "signerName": "Proveedor externo",
                      "signerEmail": null,
                      "pendingCount": 3,
                      "avgDays": 9.5
                    }
                  ],
                  "hasMore": false
                }
              }
            }
          },
          "401": {
            "description": "Falta el header `Authorization` o la API key no es válida.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "AUTHENTICATION_REQUIRED": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#AUTHENTICATION_REQUIRED",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "Provide an API key via Authorization: Bearer allsign_live_sk_….",
                      "code": "AUTHENTICATION_REQUIRED"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La API key no tiene el scope `analytics:read` (o `analytics:*`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "PERMISSION_DENIED": {
                    "summary": "Permission denied",
                    "value": {
                      "type": "https://developers.allsign.io/errors#PERMISSION_DENIED",
                      "title": "Permission denied",
                      "status": 403,
                      "detail": "This API key is missing the required scope.",
                      "code": "PERMISSION_DENIED",
                      "requiredScope": "document:write",
                      "yourScopes": [
                        "document:read"
                      ]
                    }
                  },
                  "IP_NOT_ALLOWED": {
                    "summary": "IP address not allowed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IP_NOT_ALLOWED",
                      "title": "IP address not allowed",
                      "status": 403,
                      "detail": "Access from this IP is not allowed for this API key.",
                      "code": "IP_NOT_ALLOWED"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "El parámetro no pasa la validación (ej. `period` con un valor fuera del catálogo).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "VALIDATION_ERROR": {
                    "summary": "Validation failed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#VALIDATION_ERROR",
                      "title": "Validation failed",
                      "status": 422,
                      "detail": "One or more fields are invalid.",
                      "code": "VALIDATION_ERROR"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Se superó el límite de tasa de tu API key; reintenta respetando `RateLimit-*` / `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          }
        },
        "description": "Los firmantes que más documentos tienen pendientes — quién está frenando tus flujos de firma.",
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL",
            "source": "curl \"https://api.allsign.io/v3/analytics/bottlenecks?limit=5\" \\\n  -H \"Authorization: Bearer allsign_live_sk_...\"\n"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const res = await fetch(\n  'https://api.allsign.io/v3/analytics/bottlenecks?limit=5',\n  { headers: { Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}` } },\n)\nconst { data: bottlenecks } = await res.json()\n"
          }
        ]
      }
    },
    "/analytics/team": {
      "get": {
        "tags": [
          "Analytics"
        ],
        "summary": "Team activity",
        "operationId": "analyticsTeam",
        "security": [
          {
            "Bearer Token": []
          }
        ],
        "parameters": [
          {
            "name": "period",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "pattern": "^(7d|30d|90d|12m)$",
              "description": "Time period",
              "default": "30d",
              "title": "Period"
            },
            "description": "Ventana de tiempo: `7d`, `30d`, `90d` o `12m`. Default `30d`."
          }
        ],
        "responses": {
          "200": {
            "description": "Colección acotada (`object: \"list\"`), una fila por miembro del tenant.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TeamActivityList"
                },
                "example": {
                  "object": "list",
                  "data": [
                    {
                      "userId": "usr_1a2b3c4d5e6f7g8h",
                      "name": "Ana Ramírez",
                      "initials": "AR",
                      "role": "admin",
                      "sent": 34,
                      "signed": 12,
                      "rate": 0.71
                    }
                  ],
                  "hasMore": false
                }
              }
            }
          },
          "401": {
            "description": "Falta el header `Authorization` o la API key no es válida.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "AUTHENTICATION_REQUIRED": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#AUTHENTICATION_REQUIRED",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "Provide an API key via Authorization: Bearer allsign_live_sk_….",
                      "code": "AUTHENTICATION_REQUIRED"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La API key no tiene el scope `analytics:read` (o `analytics:*`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "PERMISSION_DENIED": {
                    "summary": "Permission denied",
                    "value": {
                      "type": "https://developers.allsign.io/errors#PERMISSION_DENIED",
                      "title": "Permission denied",
                      "status": 403,
                      "detail": "This API key is missing the required scope.",
                      "code": "PERMISSION_DENIED",
                      "requiredScope": "document:write",
                      "yourScopes": [
                        "document:read"
                      ]
                    }
                  },
                  "IP_NOT_ALLOWED": {
                    "summary": "IP address not allowed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IP_NOT_ALLOWED",
                      "title": "IP address not allowed",
                      "status": 403,
                      "detail": "Access from this IP is not allowed for this API key.",
                      "code": "IP_NOT_ALLOWED"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "El parámetro no pasa la validación (ej. `period` con un valor fuera del catálogo).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "VALIDATION_ERROR": {
                    "summary": "Validation failed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#VALIDATION_ERROR",
                      "title": "Validation failed",
                      "status": 422,
                      "detail": "One or more fields are invalid.",
                      "code": "VALIDATION_ERROR"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Se superó el límite de tasa de tu API key; reintenta respetando `RateLimit-*` / `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          }
        },
        "description": "Actividad de envío y firma por cada miembro del tenant — una fila por miembro.",
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL",
            "source": "curl \"https://api.allsign.io/v3/analytics/team?period=30d\" \\\n  -H \"Authorization: Bearer allsign_live_sk_...\"\n"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const res = await fetch(\n  'https://api.allsign.io/v3/analytics/team?period=30d',\n  { headers: { Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}` } },\n)\nconst { data: team } = await res.json()\n"
          }
        ]
      }
    },
    "/analytics/events": {
      "get": {
        "tags": [
          "Analytics"
        ],
        "summary": "Recent events",
        "operationId": "analyticsEvents",
        "security": [
          {
            "Bearer Token": []
          }
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 50,
              "minimum": 1,
              "description": "Max events to return",
              "default": 8,
              "title": "Limit"
            },
            "description": "Máximo de eventos a devolver (1–50, default `8`)."
          }
        ],
        "responses": {
          "200": {
            "description": "Colección acotada (`object: \"list\"`), eventos recientes (más nuevos primero).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecentEventList"
                },
                "example": {
                  "object": "list",
                  "data": [
                    {
                      "id": "evt_7c9e6679742540de944be07fc1f90ae7",
                      "documentName": "Contrato de arrendamiento 2026.pdf",
                      "eventType": "document.completed",
                      "actorName": "Ana Ramírez",
                      "actorInitials": "AR",
                      "createdAt": "2026-07-11T20:15:00Z"
                    }
                  ],
                  "hasMore": false
                }
              }
            }
          },
          "401": {
            "description": "Falta el header `Authorization` o la API key no es válida.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "AUTHENTICATION_REQUIRED": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#AUTHENTICATION_REQUIRED",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "Provide an API key via Authorization: Bearer allsign_live_sk_….",
                      "code": "AUTHENTICATION_REQUIRED"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La API key no tiene el scope `analytics:read` (o `analytics:*`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "PERMISSION_DENIED": {
                    "summary": "Permission denied",
                    "value": {
                      "type": "https://developers.allsign.io/errors#PERMISSION_DENIED",
                      "title": "Permission denied",
                      "status": 403,
                      "detail": "This API key is missing the required scope.",
                      "code": "PERMISSION_DENIED",
                      "requiredScope": "document:write",
                      "yourScopes": [
                        "document:read"
                      ]
                    }
                  },
                  "IP_NOT_ALLOWED": {
                    "summary": "IP address not allowed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IP_NOT_ALLOWED",
                      "title": "IP address not allowed",
                      "status": 403,
                      "detail": "Access from this IP is not allowed for this API key.",
                      "code": "IP_NOT_ALLOWED"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "El parámetro no pasa la validación (ej. `period` con un valor fuera del catálogo).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "VALIDATION_ERROR": {
                    "summary": "Validation failed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#VALIDATION_ERROR",
                      "title": "Validation failed",
                      "status": 422,
                      "detail": "One or more fields are invalid.",
                      "code": "VALIDATION_ERROR"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Se superó el límite de tasa de tu API key; reintenta respetando `RateLimit-*` / `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          }
        },
        "description": "El feed de actividad reciente del tenant — los últimos eventos de documento (creado, enviado, firmado, etc.).",
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL",
            "source": "curl \"https://api.allsign.io/v3/analytics/events?limit=8\" \\\n  -H \"Authorization: Bearer allsign_live_sk_...\"\n"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const res = await fetch(\n  'https://api.allsign.io/v3/analytics/events?limit=8',\n  { headers: { Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}` } },\n)\nconst { data: events } = await res.json()\n"
          }
        ]
      }
    },
    "/signing-sessions": {
      "post": {
        "tags": [
          "Embedded Signing"
        ],
        "summary": "Create signing session",
        "description": "Acuña un `clientSecret` que autoriza al iframe a firmar como un firmante (identificado por su correo) de un documento existente. **El `clientSecret` se devuelve una sola vez, aquí.** Requiere el scope `embedded:write` y honra la cabecera `Idempotency-Key`. `livemode` sale de la key, no del body: una key `live` exige `allowedOrigins`.",
        "operationId": "createSigningSession",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SigningSessionCreateRequest"
              },
              "example": {
                "documentId": "doc_5Qr9tA3fZwLZmp3D1bCdEfG",
                "signerEmail": "firmante@empresa.com",
                "allowedOrigins": [
                  "https://app.tuempresa.com"
                ],
                "successUrl": "https://app.tuempresa.com/firma/ok"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "La sesión creada, con `clientSecret` en claro (única vez).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SigningSession"
                },
                "example": {
                  "object": "signing_session",
                  "id": "ses_3fa85f6457174562b3fc2c963f66afa6",
                  "livemode": true,
                  "status": "pending",
                  "clientSecret": "as_sess_3fa85f6457174562b3fc2c963f66afa6_secret_9f86d081884c7d659a2feaa0",
                  "document": {
                    "id": "doc_5Qr9tA3fZwLZmp3D1bCdEfG",
                    "title": "Contrato de arrendamiento 2026.pdf"
                  },
                  "signer": {
                    "email": "firmante@empresa.com",
                    "name": "Juan Pérez"
                  },
                  "expiresAt": "2026-07-12T18:04:00Z",
                  "createdAt": "2026-07-11T18:04:00Z"
                }
              }
            }
          },
          "400": {
            "description": "El identificador en un parámetro está mal formado (`INVALID_ID`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "INVALID_ID": {
                    "summary": "Malformed identifier",
                    "value": {
                      "type": "https://developers.allsign.io/errors#INVALID_ID",
                      "title": "Malformed identifier",
                      "status": 400,
                      "detail": "Invalid id; expected a typed, prefixed id (e.g. 'doc_…').",
                      "code": "INVALID_ID"
                    }
                  },
                  "IDEMPOTENCY_KEY_REQUIRED": {
                    "summary": "Idempotency key required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IDEMPOTENCY_KEY_REQUIRED",
                      "title": "Idempotency key required",
                      "status": 400,
                      "detail": "POST requests that create or charge require a unique Idempotency-Key (UUID v4).",
                      "code": "IDEMPOTENCY_KEY_REQUIRED"
                    }
                  },
                  "IDEMPOTENCY_KEY_INVALID": {
                    "summary": "Idempotency key invalid",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IDEMPOTENCY_KEY_INVALID",
                      "title": "Idempotency key invalid",
                      "status": 400,
                      "detail": "Idempotency-Key must be a UUID v4.",
                      "code": "IDEMPOTENCY_KEY_INVALID"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Falta el header `Authorization` o la API key no es válida.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "AUTHENTICATION_REQUIRED": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#AUTHENTICATION_REQUIRED",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "Provide an API key via Authorization: Bearer allsign_live_sk_….",
                      "code": "AUTHENTICATION_REQUIRED"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La API key no tiene el scope `embedded:write`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "PERMISSION_DENIED": {
                    "summary": "Permission denied",
                    "value": {
                      "type": "https://developers.allsign.io/errors#PERMISSION_DENIED",
                      "title": "Permission denied",
                      "status": 403,
                      "detail": "This API key is missing the required scope.",
                      "code": "PERMISSION_DENIED",
                      "requiredScope": "document:write",
                      "yourScopes": [
                        "document:read"
                      ]
                    }
                  },
                  "IP_NOT_ALLOWED": {
                    "summary": "IP address not allowed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IP_NOT_ALLOWED",
                      "title": "IP address not allowed",
                      "status": 403,
                      "detail": "Access from this IP is not allowed for this API key.",
                      "code": "IP_NOT_ALLOWED"
                    }
                  },
                  "DEV_FEATURE_RESTRICTED": {
                    "summary": "Feature restricted in this environment",
                    "value": {
                      "type": "https://developers.allsign.io/errors#DEV_FEATURE_RESTRICTED",
                      "title": "Feature restricted in this environment",
                      "status": 403,
                      "detail": "This feature is not available for dev/test API keys. Create a live key in your dashboard.",
                      "code": "DEV_FEATURE_RESTRICTED"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "El `documentId` no existe, o el firmante no es participante del documento (nunca filtra documentos ajenos).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RESOURCE_NOT_FOUND": {
                    "summary": "Resource not found",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RESOURCE_NOT_FOUND",
                      "title": "Resource not found",
                      "status": 404,
                      "detail": "No resource was found with that id.",
                      "code": "RESOURCE_NOT_FOUND"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Reintento con la misma `Idempotency-Key` mientras la petición original sigue en curso.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "DOCUMENT_NOT_SENDABLE": {
                    "summary": "Document not sendable",
                    "value": {
                      "type": "https://developers.allsign.io/errors#DOCUMENT_NOT_SENDABLE",
                      "title": "Document not sendable",
                      "status": 409,
                      "detail": "The document has no signature fields, or an owner variable is still pending.",
                      "code": "DOCUMENT_NOT_SENDABLE"
                    }
                  },
                  "IDEMPOTENCY_KEY_REUSED": {
                    "summary": "Idempotency key reused",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IDEMPOTENCY_KEY_REUSED",
                      "title": "Idempotency key reused",
                      "status": 409,
                      "detail": "This Idempotency-Key was already used with a different request.",
                      "code": "IDEMPOTENCY_KEY_REUSED"
                    }
                  },
                  "IDEMPOTENCY_KEY_IN_PROGRESS": {
                    "summary": "Idempotency key in progress",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IDEMPOTENCY_KEY_IN_PROGRESS",
                      "title": "Idempotency key in progress",
                      "status": 409,
                      "detail": "A request with this Idempotency-Key is still in progress.",
                      "code": "IDEMPOTENCY_KEY_IN_PROGRESS",
                      "retryAfter": 2
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Falta `allowedOrigins` en una key `live`, u otro campo inválido (`VALIDATION_ERROR`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "VALIDATION_ERROR": {
                    "summary": "Validation failed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#VALIDATION_ERROR",
                      "title": "Validation failed",
                      "status": 422,
                      "detail": "One or more fields are invalid.",
                      "code": "VALIDATION_ERROR"
                    }
                  }
                },
                "example": {
                  "type": "https://developers.allsign.io/errors#VALIDATION_ERROR",
                  "title": "Validation failed",
                  "status": 422,
                  "detail": "Live sessions require 'allowedOrigins' (the domain that embeds the iframe).",
                  "instance": "/v3/signing-sessions",
                  "code": "VALIDATION_ERROR",
                  "requestId": "req_7c9e6679742540de944be07fc1f90ae7",
                  "errors": [
                    {
                      "field": "allowedOrigins",
                      "pointer": "/allowedOrigins",
                      "code": "REQUIRED",
                      "detail": "Add the origin(s) where you mount the iframe, e.g. https://app.yourcompany.com."
                    }
                  ]
                }
              }
            }
          },
          "429": {
            "description": "Se superó el límite de tasa de tu API key; reintenta respetando `RateLimit-*` / `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer Token": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL",
            "source": "curl -X POST \"https://api.allsign.io/v3/signing-sessions\" \\\n  -H \"Authorization: Bearer allsign_live_sk_...\" \\\n  -H \"Content-Type: application/json\" \\\n  -H \"Idempotency-Key: 3fa85f64-5717-4562-b3fc-2c963f66afa6\" \\\n  -d '{\n    \"documentId\": \"doc_5Qr9tA3fZwLZmp3D1bCdEfG\",\n    \"signerEmail\": \"firmante@empresa.com\",\n    \"allowedOrigins\": [\"https://app.tuempresa.com\"],\n    \"successUrl\": \"https://app.tuempresa.com/firma/ok\"\n  }'\n"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const res = await fetch('https://api.allsign.io/v3/signing-sessions', {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}`,\n    'Content-Type': 'application/json',\n    'Idempotency-Key': crypto.randomUUID(),\n  },\n  body: JSON.stringify({\n    documentId: 'doc_5Qr9tA3fZwLZmp3D1bCdEfG',\n    signerEmail: 'firmante@empresa.com',\n    allowedOrigins: ['https://app.tuempresa.com'],\n  }),\n})\nconst session = await res.json()\n// Pasa session.clientSecret a tu iframe (se devuelve UNA sola vez)\n"
          }
        ]
      }
    },
    "/signing-sessions/{session_id}": {
      "get": {
        "tags": [
          "Embedded Signing"
        ],
        "summary": "Retrieve signing session",
        "description": "Lee el estado **autoritativo del lado del servidor** de una sesión — la verdad sobre si la firma se completó, no lo que reporte el iframe. Un `?expand=evidence` adjunta el paquete de evidencia (PDF sellado + NOM-151 + URLs prefirmadas) cuando ya existe. Requiere `embedded:write`. El `clientSecret` no se devuelve aquí (viene `null`).",
        "operationId": "getSigningSession",
        "security": [
          {
            "Bearer Token": []
          }
        ],
        "parameters": [
          {
            "name": "session_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Session Id"
            },
            "description": "ID de la sesión (`ses_…`)."
          },
          {
            "name": "expand",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Expand"
            },
            "description": "Pasa `evidence` para adjuntar el paquete de evidencia sellada. Otro valor es un **400 `INVALID_EXPAND`**."
          }
        ],
        "responses": {
          "200": {
            "description": "El objeto sesión, con evidencia si se pidió `?expand=evidence`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SigningSession"
                },
                "example": {
                  "object": "signing_session",
                  "id": "ses_3fa85f6457174562b3fc2c963f66afa6",
                  "livemode": true,
                  "status": "completed",
                  "clientSecret": null,
                  "document": {
                    "id": "doc_5Qr9tA3fZwLZmp3D1bCdEfG",
                    "title": "Contrato de arrendamiento 2026.pdf"
                  },
                  "signer": {
                    "email": "firmante@empresa.com",
                    "name": "Juan Pérez"
                  },
                  "signature": {
                    "id": "sgr_63db6fa927094f689ea7bc640194bade",
                    "status": "SIGNED",
                    "signedAt": "2026-07-11T19:02:00Z"
                  },
                  "mountedAt": "2026-07-11T18:40:00Z",
                  "completedAt": "2026-07-11T19:02:00Z",
                  "createdAt": "2026-07-11T18:04:00Z",
                  "expiresAt": "2026-07-12T18:04:00Z",
                  "evidence": {
                    "available": true,
                    "evidencePdf": {
                      "presignedUrl": "https://allsign-documents.s3.amazonaws.com/documentos/.../evidence.pdf?X-Amz-Signature=...",
                      "s3Key": "documentos/5Qr9.../pdf/evidence.pdf",
                      "hash": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"
                    },
                    "nom151": {
                      "presignedUrl": "https://allsign-documents.s3.amazonaws.com/documentos/.../constancia.tsr?X-Amz-Signature=...",
                      "s3Key": "documentos/5Qr9.../nom151/constancia.tsr",
                      "data": {
                        "serialNumber": "12345",
                        "issuedAt": "2026-07-11T19:03:00Z"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "El valor de `expand` no es `evidence` (`INVALID_EXPAND`), o un id mal formado.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "INVALID_ID": {
                    "summary": "Malformed identifier",
                    "value": {
                      "type": "https://developers.allsign.io/errors#INVALID_ID",
                      "title": "Malformed identifier",
                      "status": 400,
                      "detail": "Invalid id; expected a typed, prefixed id (e.g. 'doc_…').",
                      "code": "INVALID_ID"
                    }
                  },
                  "EXPAND_DEPTH_EXCEEDED": {
                    "summary": "Expand depth exceeded",
                    "value": {
                      "type": "https://developers.allsign.io/errors#EXPAND_DEPTH_EXCEEDED",
                      "title": "Expand depth exceeded",
                      "status": 400,
                      "detail": "At most 3 expand paths are allowed.",
                      "code": "EXPAND_DEPTH_EXCEEDED"
                    }
                  },
                  "INVALID_EXPAND": {
                    "summary": "Invalid expand path",
                    "value": {
                      "type": "https://developers.allsign.io/errors#INVALID_EXPAND",
                      "title": "Invalid expand path",
                      "status": 400,
                      "detail": "Unknown expand path.",
                      "code": "INVALID_EXPAND"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Falta el header `Authorization` o la API key no es válida.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "AUTHENTICATION_REQUIRED": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#AUTHENTICATION_REQUIRED",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "Provide an API key via Authorization: Bearer allsign_live_sk_….",
                      "code": "AUTHENTICATION_REQUIRED"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La API key no tiene el scope `embedded:write`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "PERMISSION_DENIED": {
                    "summary": "Permission denied",
                    "value": {
                      "type": "https://developers.allsign.io/errors#PERMISSION_DENIED",
                      "title": "Permission denied",
                      "status": 403,
                      "detail": "This API key is missing the required scope.",
                      "code": "PERMISSION_DENIED",
                      "requiredScope": "document:write",
                      "yourScopes": [
                        "document:read"
                      ]
                    }
                  },
                  "IP_NOT_ALLOWED": {
                    "summary": "IP address not allowed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IP_NOT_ALLOWED",
                      "title": "IP address not allowed",
                      "status": 403,
                      "detail": "Access from this IP is not allowed for this API key.",
                      "code": "IP_NOT_ALLOWED"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No existe una sesión con ese `id` en este tenant (`RESOURCE_NOT_FOUND`) — nunca filtra sesiones de otro tenant.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RESOURCE_NOT_FOUND": {
                    "summary": "Resource not found",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RESOURCE_NOT_FOUND",
                      "title": "Resource not found",
                      "status": 404,
                      "detail": "No resource was found with that id.",
                      "code": "RESOURCE_NOT_FOUND"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "El parámetro no pasa la validación (ej. `period` con un valor fuera del catálogo).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Se superó el límite de tasa de tu API key; reintenta respetando `RateLimit-*` / `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL",
            "source": "curl \"https://api.allsign.io/v3/signing-sessions/ses_3fa85f6457174562b3fc2c963f66afa6?expand=evidence\" \\\n  -H \"Authorization: Bearer allsign_live_sk_...\"\n"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const id = 'ses_3fa85f6457174562b3fc2c963f66afa6'\nconst res = await fetch(\n  `https://api.allsign.io/v3/signing-sessions/${id}?expand=evidence`,\n  { headers: { Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}` } },\n)\nconst session = await res.json()\n\nif (session.evidence?.available) {\n  const url = session.evidence.evidencePdf.presignedUrl\n}\n"
          }
        ]
      }
    },
    "/signing-sessions/{session_id}/init": {
      "post": {
        "tags": [
          "Embedded Signing"
        ],
        "summary": "Init signing session",
        "description": "Intercambia el `clientSecret` por un **guest token** fresco que arranca la firma dentro del iframe. La consume el shell de iframe de AllSign (primera parte), no tu backend. **Ruta pública — no lleva `Authorization`**: la autenticación es el `clientSecret` en el body. Volver a llamar `init` es idempotente por diseño: rota el guest token interno y da uno nuevo.",
        "operationId": "initSigningSession",
        "parameters": [
          {
            "name": "session_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Session Id"
            },
            "description": "ID de la sesión (`ses_…`)."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SigningSessionInitRequest"
              },
              "example": {
                "clientSecret": "as_sess_3fa85f6457174562b3fc2c963f66afa6_secret_9f86d081884c7d659a2feaa0",
                "parentOrigin": "https://app.tuempresa.com"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "El guest token nuevo y el contexto de la sesión para montar el iframe.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SigningSessionInit"
                },
                "example": {
                  "sessionId": "ses_3fa85f6457174562b3fc2c963f66afa6",
                  "signatureId": "sgr_63db6fa927094f689ea7bc640194bade",
                  "guestToken": "gt_7c9e6679742540de944be07fc1f90ae7",
                  "signer": {
                    "email": "firmante@empresa.com",
                    "name": "Juan Pérez"
                  },
                  "signerId": "sgr_63db6fa927094f689ea7bc640194bade",
                  "document": {
                    "id": "doc_5Qr9tA3fZwLZmp3D1bCdEfG",
                    "title": "Contrato de arrendamiento 2026.pdf"
                  },
                  "locale": "es",
                  "brandProfileId": null,
                  "successUrl": "https://app.tuempresa.com/firma/ok",
                  "cancelUrl": null,
                  "livemode": true
                }
              }
            }
          },
          "400": {
            "description": "El `clientSecret` no corresponde a esta sesión, o está mal formado.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "INVALID_ID": {
                    "summary": "Malformed identifier",
                    "value": {
                      "type": "https://developers.allsign.io/errors#INVALID_ID",
                      "title": "Malformed identifier",
                      "status": 400,
                      "detail": "Invalid id; expected a typed, prefixed id (e.g. 'doc_…').",
                      "code": "INVALID_ID"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La sesión pertenece a otro tenant, o el `parentOrigin` no está en `allowedOrigins`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "PERMISSION_DENIED": {
                    "summary": "Permission denied",
                    "value": {
                      "type": "https://developers.allsign.io/errors#PERMISSION_DENIED",
                      "title": "Permission denied",
                      "status": 403,
                      "detail": "This API key is missing the required scope.",
                      "code": "PERMISSION_DENIED",
                      "requiredScope": "document:write",
                      "yourScopes": [
                        "document:read"
                      ]
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No existe una sesión con ese `id`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RESOURCE_NOT_FOUND": {
                    "summary": "Resource not found",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RESOURCE_NOT_FOUND",
                      "title": "Resource not found",
                      "status": 404,
                      "detail": "No resource was found with that id.",
                      "code": "RESOURCE_NOT_FOUND"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "La sesión ya está `completed`, `expired` o `cancelled` — no admite un nuevo `init`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "DOCUMENT_CONFLICT": {
                    "summary": "Document conflict",
                    "value": {
                      "type": "https://developers.allsign.io/errors#DOCUMENT_CONFLICT",
                      "title": "Document conflict",
                      "status": 409,
                      "detail": "The document is not in a state that allows this operation.",
                      "code": "DOCUMENT_CONFLICT"
                    }
                  },
                  "DOCUMENT_ALREADY_SIGNED": {
                    "summary": "Document already signed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#DOCUMENT_ALREADY_SIGNED",
                      "title": "Document already signed",
                      "status": 409,
                      "detail": "The document is already fully signed.",
                      "code": "DOCUMENT_ALREADY_SIGNED"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "El parámetro no pasa la validación (ej. `period` con un valor fuera del catálogo).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "VALIDATION_ERROR": {
                    "summary": "Validation failed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#VALIDATION_ERROR",
                      "title": "Validation failed",
                      "status": 422,
                      "detail": "One or more fields are invalid.",
                      "code": "VALIDATION_ERROR"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Se superó el límite de tasa de tu API key; reintenta respetando `RateLimit-*` / `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          }
        },
        "security": [],
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL",
            "source": "curl -X POST \"https://api.allsign.io/v3/signing-sessions/ses_3fa85f6457174562b3fc2c963f66afa6/init\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"clientSecret\": \"as_sess_3fa85f6457174562b3fc2c963f66afa6_secret_9f86d081884c7d659a2feaa0\",\n    \"parentOrigin\": \"https://app.tuempresa.com\"\n  }'\n"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "// Nota: sin Authorization — el clientSecret va en el body\nconst id = 'ses_3fa85f6457174562b3fc2c963f66afa6'\nconst res = await fetch(\n  `https://api.allsign.io/v3/signing-sessions/${id}/init`,\n  {\n    method: 'POST',\n    headers: { 'Content-Type': 'application/json' },\n    body: JSON.stringify({\n      clientSecret: session.clientSecret,\n      parentOrigin: window.location.origin,\n    }),\n  },\n)\nconst init = await res.json()\n"
          }
        ]
      }
    },
    "/signing-sessions/{session_id}/policy": {
      "get": {
        "tags": [
          "Embedded Signing"
        ],
        "summary": "Get session policy",
        "description": "Consulta pública (por id, **no** por el secreto) de los orígenes autorizados a embeber el iframe. La ruta de primera parte que sirve el HTML del iframe inyecta estos valores en su header `Content-Security-Policy: frame-ancestors`. **Ruta pública — no lleva `Authorization`.** No expone el `clientSecret` ni datos del documento.",
        "operationId": "getSigningSessionPolicy",
        "parameters": [
          {
            "name": "session_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Session Id"
            },
            "description": "ID de la sesión (`ses_…`)."
          }
        ],
        "responses": {
          "200": {
            "description": "La política CSP (`allowedOrigins` + `frameAncestors`) de la sesión.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SigningSessionPolicy"
                },
                "example": {
                  "sessionId": "ses_3fa85f6457174562b3fc2c963f66afa6",
                  "allowedOrigins": [
                    "https://app.tuempresa.com"
                  ],
                  "frameAncestors": "https://app.tuempresa.com http://localhost:*"
                }
              }
            }
          },
          "400": {
            "description": "El `id` está mal formado.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "INVALID_ID": {
                    "summary": "Malformed identifier",
                    "value": {
                      "type": "https://developers.allsign.io/errors#INVALID_ID",
                      "title": "Malformed identifier",
                      "status": 400,
                      "detail": "Invalid id; expected a typed, prefixed id (e.g. 'doc_…').",
                      "code": "INVALID_ID"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No existe una sesión con ese `id`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RESOURCE_NOT_FOUND": {
                    "summary": "Resource not found",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RESOURCE_NOT_FOUND",
                      "title": "Resource not found",
                      "status": 404,
                      "detail": "No resource was found with that id.",
                      "code": "RESOURCE_NOT_FOUND"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "El parámetro no pasa la validación (ej. `period` con un valor fuera del catálogo).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Se superó el límite de tasa de tu API key; reintenta respetando `RateLimit-*` / `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          }
        },
        "security": [],
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL",
            "source": "curl \"https://api.allsign.io/v3/signing-sessions/ses_3fa85f6457174562b3fc2c963f66afa6/policy\"\n"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "const id = 'ses_3fa85f6457174562b3fc2c963f66afa6'\nconst res = await fetch(\n  `https://api.allsign.io/v3/signing-sessions/${id}/policy`,\n)\nconst { frameAncestors } = await res.json()\n"
          }
        ]
      }
    },
    "/constancias": {
      "post": {
        "tags": [
          "Constancias"
        ],
        "summary": "Emitir constancia NOM-151",
        "operationId": "createConstancia",
        "security": [
          {
            "Bearer Token": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConstanciaCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Constancia emitida. El artefacto viene **inline en base64** en `constancia`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConstanciaResponse"
                }
              }
            }
          },
          "400": {
            "description": "`Idempotency-Key` ausente o mal formada.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "IDEMPOTENCY_KEY_REQUIRED": {
                    "summary": "Idempotency key required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IDEMPOTENCY_KEY_REQUIRED",
                      "title": "Idempotency key required",
                      "status": 400,
                      "detail": "POST requests that create or charge require a unique Idempotency-Key (UUID v4).",
                      "code": "IDEMPOTENCY_KEY_REQUIRED"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Falta el header `Authorization` o la API key no es válida.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "AUTHENTICATION_REQUIRED": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#AUTHENTICATION_REQUIRED",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "Provide an API key via Authorization: Bearer allsign_live_sk_….",
                      "code": "AUTHENTICATION_REQUIRED"
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "Créditos insuficientes en el tenant (`INSUFFICIENT_CREDITS`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "INSUFFICIENT_CREDITS": {
                    "summary": "Insufficient credits",
                    "value": {
                      "type": "https://developers.allsign.io/errors#INSUFFICIENT_CREDITS",
                      "title": "Insufficient credits",
                      "status": 402,
                      "detail": "This tenant does not have enough credits for this operation.",
                      "code": "INSUFFICIENT_CREDITS"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La API key no tiene el scope requerido (`constancia:read` / `constancia:write`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "CONTRACT_REQUIRED": {
                    "summary": "NOM-151 contract required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#CONTRACT_REQUIRED",
                      "title": "NOM-151 contract required",
                      "status": 403,
                      "detail": "This tenant has not enabled the NOM-151 standalone addon.",
                      "code": "CONTRACT_REQUIRED"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "El `hashSha256` no es hexadecimal de 64 caracteres.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit excedido. Reintenta respetando `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "El PSC (SeguriData) no respondió. No se cobró: la reserva de créditos se liberó. Reintenta con la MISMA `Idempotency-Key`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "SEGURIDATA_UNAVAILABLE": {
                    "summary": "Constancia provider unavailable",
                    "value": {
                      "type": "https://developers.allsign.io/errors#SEGURIDATA_UNAVAILABLE",
                      "title": "Constancia provider unavailable",
                      "status": 503,
                      "detail": "The constancia provider is temporarily unavailable. Retry with the same Idempotency-Key.",
                      "code": "SEGURIDATA_UNAVAILABLE"
                    }
                  }
                }
              }
            }
          }
        },
        "description": "Emite una **Constancia de Conservación NOM-151** a partir del hash SHA-256 de tu documento. **Tu documento nunca sale de tu infraestructura.**\n\nNo es una restricción nuestra: la NOM-151-SCFI-2016 lo **ordena**. Apéndice Normativo A, numeral A.2.4 — *«el Prestador de Servicios de Certificación únicamente recibirá la huella digital electrónica del mensaje de datos»*. Usa este endpoint si ya firmas por tu cuenta (e.firma del SAT, tu propio flujo) y solo necesitas la prueba legal del momento en que el documento existió.\n\n**El hash** va en hexadecimal minúsculas de 64 caracteres — exactamente lo que produce `sha256sum archivo.pdf`. Se aceptan mayúsculas y se normalizan; **no** se acepta base64 ni prefijos tipo `sha256:`.\n\n**`Idempotency-Key` es obligatoria.** Este endpoint cobra y llama a un PSC externo: sin la key, un timeout de red te deja sin forma segura de reintentar. Reintentar con la misma key devuelve la primera respuesta, nunca emite dos veces.\n\n**`externalId`** es tu propia referencia (el folio de tu expediente). Te sirve para recuperar la constancia después sin haber guardado nuestro `id`, y como segunda red contra el doble cobro. Reusar un `externalId` **con el mismo hash** devuelve la constancia ya emitida; reusarlo **con otro hash** devuelve `409` — la referencia ya está tomada por otro documento, y devolverte la constancia equivocada sería peor que fallar.\n\n**Facturación y entornos.** En `live` consume créditos y llama al PSC. Con una API key `test` o `dev` no cobra, no contacta al PSC y devuelve un artefacto **sin validez legal**, marcado con `sandbox: true` y `livemode: false`.\n\n**Requiere contrato.** El addon se activa por tenant tras firmar el contrato de prestación de servicio; sin él, `live` responde `403 CONTRACT_REQUIRED`.",
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL",
            "source": "# El hash lo calculas TÚ; el documento no viaja.\nHASH=$(sha256sum contrato.pdf | cut -d\" \" -f1)\n\ncurl \"https://api.allsign.io/v3/constancias\" \\\n  -H \"Authorization: Bearer allsign_live_sk_...\" \\\n  -H \"Content-Type: application/json\" \\\n  -H \"Idempotency-Key: 9f3c1a2e-8d4b-4c6a-9e21-5b7f0d8a3c14\" \\\n  -d \"{\\\"hashSha256\\\":\\\"$HASH\\\",\\\"externalId\\\":\\\"expediente-2026-0412\\\",\\\"label\\\":\\\"Contrato de arrendamiento\\\"}\"\n"
          },
          {
            "lang": "typescript",
            "label": "TypeScript",
            "source": "import { createHash, randomUUID } from 'node:crypto'\nimport { readFile } from 'node:fs/promises'\n\n// El documento nunca sale de tu infraestructura: solo el hash.\nconst hashSha256 = createHash('sha256')\n  .update(await readFile('contrato.pdf'))\n  .digest('hex')\n\nconst res = await fetch('https://api.allsign.io/v3/constancias', {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}`,\n    'Content-Type': 'application/json',\n    // Obligatoria: este endpoint cobra y llama a un PSC externo.\n    'Idempotency-Key': randomUUID(),\n  },\n  body: JSON.stringify({\n    hashSha256,\n    externalId: 'expediente-2026-0412',\n    label: 'Contrato de arrendamiento',\n  }),\n})\n\nconst constancia = await res.json()\n// Archiva el base64, NO el downloadUrl (ese caduca).\nawait writeFile('constancia.der', Buffer.from(constancia.constancia, 'base64'))\n"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import base64, hashlib, os, uuid, requests\n\n# El documento no viaja: solo su huella.\nwith open(\"contrato.pdf\", \"rb\") as f:\n    hash_sha256 = hashlib.sha256(f.read()).hexdigest()\n\nres = requests.post(\n    \"https://api.allsign.io/v3/constancias\",\n    headers={\n        \"Authorization\": f\"Bearer {os.environ['ALLSIGN_API_KEY']}\",\n        \"Idempotency-Key\": str(uuid.uuid4()),\n    },\n    json={\n        \"hashSha256\": hash_sha256,\n        \"externalId\": \"expediente-2026-0412\",\n        \"label\": \"Contrato de arrendamiento\",\n    },\n    timeout=15,  # el PSC responde en ~1-2s; deja margen\n)\nconstancia = res.json()\n\n# Archiva el artefacto, no el enlace de descarga.\nwith open(\"constancia.der\", \"wb\") as f:\n    f.write(base64.b64decode(constancia[\"constancia\"]))\n"
          }
        ]
      },
      "get": {
        "tags": [
          "Constancias"
        ],
        "summary": "Listar constancias",
        "operationId": "listConstancias",
        "security": [
          {
            "Bearer Token": []
          }
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 100,
              "minimum": 1,
              "default": 20,
              "title": "Limit"
            }
          },
          {
            "name": "startingAfter",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Startingafter"
            }
          },
          {
            "name": "externalId",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Externalid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Página de constancias (sin el artefacto — ver la nota arriba).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConstanciaList"
                }
              }
            }
          },
          "401": {
            "description": "Falta el header `Authorization` o la API key no es válida.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "AUTHENTICATION_REQUIRED": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#AUTHENTICATION_REQUIRED",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "Provide an API key via Authorization: Bearer allsign_live_sk_….",
                      "code": "AUTHENTICATION_REQUIRED"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La API key no tiene el scope requerido (`constancia:read` / `constancia:write`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "PERMISSION_DENIED": {
                    "summary": "Permission denied",
                    "value": {
                      "type": "https://developers.allsign.io/errors#PERMISSION_DENIED",
                      "title": "Permission denied",
                      "status": 403,
                      "detail": "This API key is missing the required scope.",
                      "code": "PERMISSION_DENIED",
                      "requiredScope": "document:write",
                      "yourScopes": [
                        "document:read"
                      ]
                    }
                  },
                  "IP_NOT_ALLOWED": {
                    "summary": "IP address not allowed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IP_NOT_ALLOWED",
                      "title": "IP address not allowed",
                      "status": 403,
                      "detail": "Access from this IP is not allowed for this API key.",
                      "code": "IP_NOT_ALLOWED"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "`limit` fuera del rango 1–100.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "VALIDATION_ERROR": {
                    "summary": "Validation failed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#VALIDATION_ERROR",
                      "title": "Validation failed",
                      "status": 422,
                      "detail": "One or more fields are invalid.",
                      "code": "VALIDATION_ERROR"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit excedido. Reintenta respetando `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          }
        },
        "description": "Lista las constancias del tenant, más recientes primero, con paginación por cursor.\n\n**El listado NO trae el artefacto.** Devolver el base64 de hasta 100 constancias por página significaría descargarlas todas de nuestro almacenamiento en cada petición. Para el artefacto usa `GET /v3/constancias/{constanciaId}`, que trae uno.\n\nSirve para **conciliar**: filtra por tu `externalId` para encontrar el expediente que buscas, o pagina el periodo completo para cuadrar lo emitido contra lo cobrado.\n\nPaginación: manda `startingAfter` con el `nextCursor` de la respuesta anterior. `hasMore` te dice si vale la pena pedir otra página.\n\nEl listado está **acotado al entorno de tu API key**: una key `test` no ve las constancias `live` del tenant, ni al revés.",
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL (buscar por tu referencia)",
            "source": "curl \"https://api.allsign.io/v3/constancias\"?externalId=expediente-2026-0412\" \\\n  -H \"Authorization: Bearer allsign_live_sk_...\"\n"
          },
          {
            "lang": "typescript",
            "label": "TypeScript (paginar todo el periodo)",
            "source": "// Conciliación: recorre todas las páginas con el cursor.\nlet cursor: string | undefined\nconst todas = []\n\ndo {\n  const qs = new URLSearchParams({ limit: '100' })\n  if (cursor) qs.set('startingAfter', cursor)\n\n  const res = await fetch(`https://api.allsign.io/v3/constancias?${qs}`, {\n    headers: { Authorization: `Bearer ${process.env.ALLSIGN_API_KEY}` },\n  })\n  const page = await res.json()\n\n  todas.push(...page.data)\n  cursor = page.hasMore ? page.nextCursor : undefined\n} while (cursor)\n\n// Los items NO traen el artefacto: para eso, GET /constancias/{id}\n"
          }
        ]
      }
    },
    "/constancias/certchain": {
      "get": {
        "tags": [
          "Constancias"
        ],
        "summary": "Raíz de confianza para verificar offline",
        "operationId": "getConstanciaCertchain",
        "responses": {
          "200": {
            "description": "El certificado raíz en PEM."
          },
          "401": {
            "description": "Falta el header `Authorization` o la API key no es válida.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "AUTHENTICATION_REQUIRED": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#AUTHENTICATION_REQUIRED",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "Provide an API key via Authorization: Bearer allsign_live_sk_….",
                      "code": "AUTHENTICATION_REQUIRED"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La API key no tiene el scope requerido (`constancia:read` / `constancia:write`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "PERMISSION_DENIED": {
                    "summary": "Permission denied",
                    "value": {
                      "type": "https://developers.allsign.io/errors#PERMISSION_DENIED",
                      "title": "Permission denied",
                      "status": 403,
                      "detail": "This API key is missing the required scope.",
                      "code": "PERMISSION_DENIED",
                      "requiredScope": "document:write",
                      "yourScopes": [
                        "document:read"
                      ]
                    }
                  },
                  "IP_NOT_ALLOWED": {
                    "summary": "IP address not allowed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IP_NOT_ALLOWED",
                      "title": "IP address not allowed",
                      "status": 403,
                      "detail": "Access from this IP is not allowed for this API key.",
                      "code": "IP_NOT_ALLOWED"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit excedido. Reintenta respetando `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "SERVICE_UNAVAILABLE": {
                    "summary": "Service Unavailable",
                    "value": {
                      "type": "https://developers.allsign.io/errors#SERVICE_UNAVAILABLE",
                      "title": "Service Unavailable",
                      "status": 503,
                      "detail": "Service Unavailable",
                      "code": "SERVICE_UNAVAILABLE"
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer Token": []
          }
        ],
        "description": "Devuelve en PEM el certificado raíz de la **Autoridad Certificadora Raíz Segunda de Secretaría de Economía** — el `-CAfile` que necesitas para verificar una constancia sin depender de AllSign.\n\n⚠️ **`openssl ts -verify` rechaza una constancia NOM-151 con la invocación normal.** No es que la constancia esté mal: el certificado firmante **no lleva el Extended Key Usage `Time Stamping`** (solo `Digital Signature, Non Repudiation`), porque una constancia de conservación no es un sello de tiempo puro. Sin el flag correcto verás `unsuitable certificate purpose` y concluirás, equivocadamente, que la constancia es inválida.\n\nEl flag es **`-purpose any`**. Y como SeguriData entrega un **token CMS pelado** (no un `TimeStampResp`), hace falta además **`-token_in`**.\n\nSi tu versión de `openssl` aun así se niega, `openssl cms -verify -purpose any` comprueba firma y cadena — **pero no compara el message imprint**, así que en ese camino tienes que extraer el `TSTInfo` y comparar el hash tú mismo.\n\n> Servimos esta raíz **por conveniencia, no como autoridad**: no somos PSC acreditado. La fuente autoritativa es la Secretaría de Economía; si tu proceso requiere rigor, bájala de ahí y compara. El archivo que servimos se valida contra su fingerprint SHA-256 antes de entregarse.",
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL",
            "source": "curl -s https://api.allsign.io/v3/constancias/certchain -o economia_root.pem\n\n# Comprueba que es la raíz que esperas antes de confiar en ella:\nopenssl x509 -in economia_root.pem -noout -subject -fingerprint -sha256\n"
          }
        ]
      }
    },
    "/constancias/verify": {
      "post": {
        "tags": [
          "Constancias"
        ],
        "summary": "Verificar una constancia",
        "operationId": "verifyConstancia",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VerifyRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Resultado de la verificación. Revisa `status` **y** `checks`; un `INDETERMINATE` con `errors` te dice qué no se pudo comprobar.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VerifyResponse"
                }
              }
            }
          },
          "401": {
            "description": "Falta el header `Authorization` o la API key no es válida.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "AUTHENTICATION_REQUIRED": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#AUTHENTICATION_REQUIRED",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "Provide an API key via Authorization: Bearer allsign_live_sk_….",
                      "code": "AUTHENTICATION_REQUIRED"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La API key no tiene el scope requerido (`constancia:read` / `constancia:write`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "PERMISSION_DENIED": {
                    "summary": "Permission denied",
                    "value": {
                      "type": "https://developers.allsign.io/errors#PERMISSION_DENIED",
                      "title": "Permission denied",
                      "status": 403,
                      "detail": "This API key is missing the required scope.",
                      "code": "PERMISSION_DENIED",
                      "requiredScope": "document:write",
                      "yourScopes": [
                        "document:read"
                      ]
                    }
                  },
                  "IP_NOT_ALLOWED": {
                    "summary": "IP address not allowed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IP_NOT_ALLOWED",
                      "title": "IP address not allowed",
                      "status": 403,
                      "detail": "Access from this IP is not allowed for this API key.",
                      "code": "IP_NOT_ALLOWED"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "El `constanciaId` no existe o pertenece a otro tenant.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "CONSTANCIA_NOT_FOUND": {
                    "summary": "Constancia not found",
                    "value": {
                      "type": "https://developers.allsign.io/errors#CONSTANCIA_NOT_FOUND",
                      "title": "Constancia not found",
                      "status": 404,
                      "detail": "No constancia was found with that id.",
                      "code": "CONSTANCIA_NOT_FOUND"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Falta `constancia`/`constanciaId`, o `hashSha256` cuando mandas el artefacto inline.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "VALIDATION_ERROR": {
                    "summary": "Validation failed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#VALIDATION_ERROR",
                      "title": "Validation failed",
                      "status": 422,
                      "detail": "One or more fields are invalid.",
                      "code": "VALIDATION_ERROR"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit excedido. Reintenta respetando `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer Token": []
          }
        ],
        "description": "Corre los **cuatro** checks criptográficos sobre una constancia y devuelve el resultado por criterio.\n\n| Check | Qué prueba |\n|---|---|\n| `integrity` | El hash sellado dentro del token es el de tu documento |\n| `chainOfTrust` | El certificado firmante encadena a la raíz de **Secretaría de Economía** |\n| `cmsSignature` | La firma CMS del token es válida (RFC 5652) |\n| `certValidity` | El certificado estaba vigente **al momento del sellado** |\n\nLos cuatro son necesarios y ninguno implica a otro: un imprint correcto no dice nada de quién firmó, y una firma válida de un emisor cualquiera no acredita nada.\n\n**`status` es tri-estado, no un booleano** (ETSI EN 319 102-1):\n\n- `VALID` — los cuatro checks pasaron.\n- `INVALID` — afirmación fuerte: el artefacto está mal (el documento no es el que se selló, o el emisor no es acreditado).\n- `INDETERMINATE` — **no pudimos concluir**. Token ilegible, o un check que no se pudo completar. *No* significa que la constancia sea falsa.\n\nEsa distinción importa: colapsar `INDETERMINATE` en `INVALID` te haría reportar «tu constancia es falsa» cuando el problema es de nuestro lado.\n\n> **Esto es una conveniencia, no una autoridad.** AllSign no es PSC acreditado, y preguntarle al emisor si su propio artefacto es válido no constituye prueba ante un tercero. Para eso está la verificación independiente: baja la raíz en `/v3/constancias/certchain` y verifica con `openssl` por tu cuenta. El valor de este endpoint es que valida el certificado del PSC contra la raíz correcta, que es el paso que se suele equivocar.\n\nPuedes mandar `constancia` (base64) + `hashSha256`, **o** solo `constanciaId` si la emitimos nosotros — en ese caso el hash sale de nuestro registro.",
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL (por id)",
            "source": "curl \"https://api.allsign.io/v3/constancias\"/verify \\\n  -H \"Authorization: Bearer allsign_live_sk_...\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"constanciaId\": \"cst_1a2b3c4d5e6f708192a3b4c5d6e7f809\"}'\n\n# Revisa `status` Y `checks`. Un INDETERMINATE no dice \"es falsa\":\n# dice \"no se pudo concluir\" — y `errors` explica qué faltó.\n"
          },
          {
            "lang": "shell",
            "label": "Verificación INDEPENDIENTE (sin AllSign)",
            "source": "# La que vale ante un tercero: no depende de que AllSign confirme nada.\ncurl -s https://api.allsign.io/v3/constancias/certchain -o economia_root.pem\n\nHASH=$(sha256sum contrato.pdf | cut -d' ' -f1)\n\n# `-purpose any` es OBLIGATORIO: el cert firmante de una constancia NOM-151\n# no lleva el EKU `Time Stamping`, y sin el flag openssl la rechaza con\n# `unsuitable certificate purpose`. `-token_in` porque el artefacto es un\n# token CMS pelado, no un TimeStampResp.\nopenssl ts -verify -purpose any -token_in \\\n  -in constancia.der \\\n  -digest \"$HASH\" \\\n  -CAfile economia_root.pem\n"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os, requests\n\nres = requests.post(\n    \"https://api.allsign.io/v3/constancias/verify\",\n    headers={\"Authorization\": f\"Bearer {os.environ['ALLSIGN_API_KEY']}\"},\n    json={\"constanciaId\": \"cst_1a2b3c4d5e6f708192a3b4c5d6e7f809\"},\n    timeout=15,\n)\nr = res.json()\n\nif r[\"status\"] == \"VALID\":\n    print(\"los cuatro checks pasaron; sellada el\", r[\"sealedAt\"])\nelif r[\"status\"] == \"INVALID\":\n    print(\"el artefacto está mal:\", r[\"errors\"])\nelse:\n    # INDETERMINATE — no concluyente. NO reportar como falsa.\n    print(\"no se pudo concluir:\", r[\"errors\"], r[\"checks\"])\n"
          }
        ]
      }
    },
    "/constancias/{constancia_id}": {
      "get": {
        "tags": [
          "Constancias"
        ],
        "summary": "Recuperar una constancia",
        "operationId": "getConstancia",
        "security": [
          {
            "Bearer Token": []
          }
        ],
        "parameters": [
          {
            "name": "constancia_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Constancia Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "La constancia, con el artefacto inline.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConstanciaResponse"
                }
              }
            }
          },
          "400": {
            "description": "Malformed identifier",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "INVALID_ID": {
                    "summary": "Malformed identifier",
                    "value": {
                      "type": "https://developers.allsign.io/errors#INVALID_ID",
                      "title": "Malformed identifier",
                      "status": 400,
                      "detail": "Invalid id; expected a typed, prefixed id (e.g. 'doc_…').",
                      "code": "INVALID_ID"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Falta el header `Authorization` o la API key no es válida.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "AUTHENTICATION_REQUIRED": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://developers.allsign.io/errors#AUTHENTICATION_REQUIRED",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "Provide an API key via Authorization: Bearer allsign_live_sk_….",
                      "code": "AUTHENTICATION_REQUIRED"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La API key no tiene el scope requerido (`constancia:read` / `constancia:write`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "PERMISSION_DENIED": {
                    "summary": "Permission denied",
                    "value": {
                      "type": "https://developers.allsign.io/errors#PERMISSION_DENIED",
                      "title": "Permission denied",
                      "status": 403,
                      "detail": "This API key is missing the required scope.",
                      "code": "PERMISSION_DENIED",
                      "requiredScope": "document:write",
                      "yourScopes": [
                        "document:read"
                      ]
                    }
                  },
                  "IP_NOT_ALLOWED": {
                    "summary": "IP address not allowed",
                    "value": {
                      "type": "https://developers.allsign.io/errors#IP_NOT_ALLOWED",
                      "title": "IP address not allowed",
                      "status": 403,
                      "detail": "Access from this IP is not allowed for this API key.",
                      "code": "IP_NOT_ALLOWED"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No existe una constancia con ese id en tu tenant.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "CONSTANCIA_NOT_FOUND": {
                    "summary": "Constancia not found",
                    "value": {
                      "type": "https://developers.allsign.io/errors#CONSTANCIA_NOT_FOUND",
                      "title": "Constancia not found",
                      "status": 404,
                      "detail": "No constancia was found with that id.",
                      "code": "CONSTANCIA_NOT_FOUND"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit excedido. Reintenta respetando `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "RATE_LIMITED": {
                    "summary": "Rate limited",
                    "value": {
                      "type": "https://developers.allsign.io/errors#RATE_LIMITED",
                      "title": "Rate limited",
                      "status": 429,
                      "detail": "Rate limit exceeded. Limit: 300 requests per minute.",
                      "code": "RATE_LIMITED",
                      "retryAfter": 42
                    }
                  }
                }
              }
            }
          }
        },
        "description": "Devuelve una constancia que emitimos, con el **artefacto inline en base64** — así que basta con haber guardado el `id` (o tu `externalId`) para recuperarla meses después.\n\n**Archiva `constancia`, no `downloadUrl`.** La URL de descarga es una conveniencia con caducidad (`downloadUrlExpiresAt`); si guardas el JSON con la URL y vuelves después, te queda un enlace muerto. El base64 es la fuente de verdad y no expira.\n\nLos campos `sealedAt`, `serialNumber`, `policyOid` y `tsaName` se extraen **del interior del token**, donde están cubiertos por la firma — no del JSON que envuelve la respuesta del PSC. `sealedAt` es el `genTime` del sello: el instante con valor legal.\n\nCon `Accept: application/pkcs7-mime` la misma ruta devuelve el **DER crudo** en vez del JSON, listo para pasárselo a `openssl` sin decodificar nada.",
        "x-codeSamples": [
          {
            "lang": "shell",
            "label": "cURL (JSON)",
            "source": "curl \"https://api.allsign.io/v3/constancias\"/cst_1a2b3c4d5e6f708192a3b4c5d6e7f809 \\\n  -H \"Authorization: Bearer allsign_live_sk_...\"\n"
          },
          {
            "lang": "shell",
            "label": "cURL (DER crudo, para openssl)",
            "source": "curl \"https://api.allsign.io/v3/constancias\"/cst_1a2b3c4d5e6f708192a3b4c5d6e7f809 \\\n  -H \"Authorization: Bearer allsign_live_sk_...\" \\\n  -H \"Accept: application/pkcs7-mime\" \\\n  -o constancia.der\n"
          }
        ]
      }
    }
  },
  "components": {
    "schemas": {
      "AnalyticsKPIs": {
        "properties": {
          "totalDocs": {
            "type": "integer",
            "title": "Totaldocs",
            "description": "Documentos creados en el periodo."
          },
          "completed": {
            "type": "integer",
            "title": "Completed",
            "description": "Documentos con todas las firmas completas."
          },
          "pending": {
            "type": "integer",
            "title": "Pending",
            "description": "Documentos aún esperando firmas."
          },
          "expired": {
            "type": "integer",
            "title": "Expired",
            "description": "Documentos que vencieron sin completarse."
          },
          "completionRate": {
            "type": "number",
            "title": "Completionrate",
            "description": "Porcentaje de completados sobre el total (0–100)."
          },
          "avgSignTimeHours": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Avgsigntimehours",
            "description": "Horas promedio entre el envío y la última firma. `null` si aún no hay documentos completados en el periodo."
          }
        },
        "type": "object",
        "required": [
          "totalDocs",
          "completed",
          "pending",
          "expired",
          "completionRate"
        ],
        "title": "AnalyticsKPIs",
        "description": "Key performance indicators for a tenant's signing activity.\n\nFlat object (not a list envelope) — same shape v2's\n``AnalyticsKPIsResponse`` already had."
      },
      "Bottleneck": {
        "properties": {
          "signerName": {
            "type": "string",
            "title": "Signername",
            "description": "Nombre del firmante."
          },
          "signerEmail": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Signeremail",
            "description": "Correo del firmante, si se conoce."
          },
          "pendingCount": {
            "type": "integer",
            "title": "Pendingcount",
            "description": "Firmas pendientes de esta persona."
          },
          "avgDays": {
            "type": "number",
            "title": "Avgdays",
            "description": "Días promedio que llevan pendientes."
          }
        },
        "type": "object",
        "required": [
          "signerName",
          "pendingCount",
          "avgDays"
        ],
        "title": "Bottleneck",
        "description": "A signer with the most pending signatures."
      },
      "BottleneckList": {
        "properties": {
          "object": {
            "type": "string",
            "const": "list",
            "title": "Object",
            "description": "Siempre `\"list\"`.",
            "default": "list"
          },
          "data": {
            "items": {
              "$ref": "#/components/schemas/Bottleneck"
            },
            "type": "array",
            "title": "Data",
            "description": "Firmantes ordenados por firmas pendientes."
          },
          "hasMore": {
            "type": "boolean",
            "title": "Hasmore",
            "description": "Siempre `false` — la lista la acota `limit`, no un cursor.",
            "default": false
          },
          "nextCursor": {
            "type": "null",
            "title": "Nextcursor",
            "description": "Siempre `null` — esta colección no pagina."
          },
          "previousCursor": {
            "type": "null",
            "title": "Previouscursor",
            "description": "Siempre `null` — esta colección no pagina."
          },
          "limit": {
            "type": "integer",
            "title": "Limit",
            "description": "El límite aplicado a esta respuesta."
          }
        },
        "type": "object",
        "required": [
          "data",
          "limit"
        ],
        "title": "BottleneckList",
        "description": "Bounded, non-paginated collection — ``?limit=`` bounded (default 5, max 20).\nSame envelope keys as a cursor-paginated list (F1.6): ``limit`` echoes the\nactual applied value here, not ``null``."
      },
      "BulkDeleteItemStatus": {
        "type": "string",
        "enum": [
          "deleted",
          "error"
        ],
        "title": "BulkDeleteItemStatus",
        "description": "Per-document outcome. Open enum (F1.4) — same vocabulary shape as\nBulkSendItemStatus on purpose (F1.5: bulk-delete/bulk-send used to speak\ntwo different vocabularies for the same \"result per item of a bulk op\"\nconcept; unified here).\n\nOpen enum: clients MUST tolerate values not in this list.",
        "x-extensible-enum": true
      },
      "BulkDeleteRequest": {
        "properties": {
          "documentIds": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "maxItems": 100,
            "minItems": 1,
            "title": "Documentids",
            "description": "IDs de los documentos a eliminar (`doc_…`, máximo 100 por petición)."
          }
        },
        "type": "object",
        "required": [
          "documentIds"
        ],
        "title": "BulkDeleteRequest"
      },
      "BulkDeleteResponse": {
        "properties": {
          "totalCount": {
            "type": "integer",
            "title": "Totalcount",
            "description": "Documentos pedidos."
          },
          "successCount": {
            "type": "integer",
            "title": "Successcount",
            "description": "Cuántos se eliminaron."
          },
          "errorCount": {
            "type": "integer",
            "title": "Errorcount",
            "description": "Cuántos no se pudieron eliminar."
          },
          "items": {
            "items": {
              "$ref": "#/components/schemas/BulkDeleteResultItem"
            },
            "type": "array",
            "title": "Items",
            "description": "Resultado por documento, en el orden pedido."
          }
        },
        "type": "object",
        "required": [
          "totalCount",
          "successCount",
          "errorCount",
          "items"
        ],
        "title": "BulkDeleteResponse",
        "description": "Same envelope vocabulary as BulkSendResponse (F1.5): `totalCount`/\n`successCount`/`errorCount`/`items[]`, not `deletedCount`/`failedCount`/\n`results[]` — one shape for \"result of a bulk op\" across the API."
      },
      "BulkDeleteResultItem": {
        "properties": {
          "documentId": {
            "type": "string",
            "title": "Documentid",
            "description": "El id tal como se envió en la petición."
          },
          "status": {
            "$ref": "#/components/schemas/BulkDeleteItemStatus"
          },
          "error": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Error",
            "description": "Motivo si `status` es `error` (id inválido, no encontrado, no eliminable)."
          }
        },
        "type": "object",
        "required": [
          "documentId",
          "status"
        ],
        "title": "BulkDeleteResultItem",
        "description": "Per-document outcome — a bulk delete is partial-success by design."
      },
      "BulkSendItemResult": {
        "properties": {
          "recipientEmail": {
            "type": "string",
            "title": "Recipientemail",
            "description": "El correo tal como se envió en la petición."
          },
          "documentId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Documentid",
            "description": "ID del documento creado (`doc_…`). `null` si este destinatario falló."
          },
          "status": {
            "$ref": "#/components/schemas/BulkSendItemStatus"
          },
          "error": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Error",
            "description": "Motivo si `status` es `error`."
          }
        },
        "type": "object",
        "required": [
          "recipientEmail",
          "status"
        ],
        "title": "BulkSendItemResult"
      },
      "BulkSendItemStatus": {
        "type": "string",
        "enum": [
          "pending",
          "sent",
          "created",
          "error"
        ],
        "title": "BulkSendItemStatus",
        "description": "Per-recipient outcome. Open enum — see BulkSendStatus.\n\nOpen enum: clients MUST tolerate values not in this list.",
        "x-extensible-enum": true
      },
      "BulkSendRecipient": {
        "properties": {
          "email": {
            "type": "string",
            "title": "Email",
            "description": "Correo del destinatario."
          },
          "name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Name",
            "description": "Nombre del destinatario (opcional)."
          }
        },
        "type": "object",
        "required": [
          "email"
        ],
        "title": "BulkSendRecipient",
        "description": "Email-only by design — the underlying service doesn't support WhatsApp\nfor bulk sends (single shared PDF, one email template per recipient)."
      },
      "BulkSendRequest": {
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 255,
            "minLength": 1,
            "title": "Name",
            "description": "Nombre del documento (aparece en el email de invitación de cada destinatario)."
          },
          "file": {
            "$ref": "#/components/schemas/FileInput",
            "description": "El PDF a enviar — el mismo archivo para todos los destinatarios."
          },
          "recipients": {
            "items": {
              "$ref": "#/components/schemas/BulkSendRecipient"
            },
            "type": "array",
            "maxItems": 200,
            "minItems": 1,
            "title": "Recipients",
            "description": "Destinatarios; cada uno recibe su propio documento y enlace de firma. Máximo 200."
          },
          "signatureValidation": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/SignatureValidationConfig"
              },
              {
                "type": "null"
              }
            ],
            "description": "Nivel de validez legal, aplicado a cada documento del lote."
          },
          "sendInvites": {
            "type": "boolean",
            "title": "Sendinvites",
            "description": "Si es `false`, crea los documentos sin despachar la invitación de firma todavía.",
            "default": true
          }
        },
        "type": "object",
        "required": [
          "name",
          "file",
          "recipients"
        ],
        "title": "BulkSendRequest"
      },
      "BulkSendResponse": {
        "properties": {
          "livemode": {
            "type": "boolean",
            "title": "Livemode",
            "description": "`true` en entorno `live`, `false` en `test`/`dev` (marca de agua, sin validez legal)."
          },
          "id": {
            "type": "string",
            "title": "Id",
            "description": "ID del lote de envío (`bat_…`)."
          },
          "status": {
            "$ref": "#/components/schemas/BulkSendStatus"
          },
          "totalCount": {
            "type": "integer",
            "title": "Totalcount",
            "description": "Destinatarios pedidos."
          },
          "successCount": {
            "type": "integer",
            "title": "Successcount",
            "description": "Documentos creados exitosamente."
          },
          "errorCount": {
            "type": "integer",
            "title": "Errorcount",
            "description": "Destinatarios que fallaron — ver `items[].error`."
          },
          "items": {
            "items": {
              "$ref": "#/components/schemas/BulkSendItemResult"
            },
            "type": "array",
            "title": "Items",
            "description": "Resultado por destinatario, en el orden pedido."
          }
        },
        "type": "object",
        "required": [
          "livemode",
          "id",
          "status",
          "totalCount",
          "successCount",
          "errorCount",
          "items"
        ],
        "title": "BulkSendResponse"
      },
      "BulkSendStatus": {
        "type": "string",
        "enum": [
          "processing",
          "completed",
          "partial_error"
        ],
        "title": "BulkSendStatus",
        "description": "Batch-level outcome.\n\n`createBulkSend` is asynchronous: it returns `processing` immediately and the\nclient polls `getBulkSend` until `completed` or `partialError`. Open enum\n(`x-extensible-enum`) — a tolerant reader must not hard-fail on a value it\ndoesn't recognise.\n\nOpen enum: clients MUST tolerate values not in this list.",
        "x-extensible-enum": true
      },
      "ConstanciaCreate": {
        "properties": {
          "hashSha256": {
            "type": "string",
            "maxLength": 64,
            "minLength": 64,
            "title": "Hashsha256",
            "description": "SHA-256 hex del documento."
          },
          "externalId": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 255
              },
              {
                "type": "null"
              }
            ],
            "title": "Externalid"
          },
          "label": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 255
              },
              {
                "type": "null"
              }
            ],
            "title": "Label"
          }
        },
        "type": "object",
        "required": [
          "hashSha256"
        ],
        "title": "ConstanciaCreate"
      },
      "ConstanciaList": {
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/ConstanciaResponse"
            },
            "type": "array",
            "title": "Data"
          },
          "hasMore": {
            "type": "boolean",
            "title": "Hasmore"
          }
        },
        "type": "object",
        "required": [
          "data",
          "hasMore"
        ],
        "title": "ConstanciaList"
      },
      "ConstanciaResponse": {
        "properties": {
          "livemode": {
            "type": "boolean",
            "title": "Livemode",
            "description": "`true` en entorno `live`, `false` en `test`/`dev` (marca de agua, sin validez legal)."
          },
          "id": {
            "type": "string",
            "title": "Id"
          },
          "hashSha256": {
            "type": "string",
            "title": "Hashsha256"
          },
          "externalId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Externalid"
          },
          "label": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Label"
          },
          "constancia": {
            "type": "string",
            "title": "Constancia"
          },
          "constanciaEncoding": {
            "type": "string",
            "const": "base64",
            "title": "Constanciaencoding",
            "default": "base64"
          },
          "constanciaMediaType": {
            "type": "string",
            "title": "Constanciamediatype",
            "default": "application/pkcs7-mime"
          },
          "constanciaSha256": {
            "type": "string",
            "title": "Constanciasha256"
          },
          "serialNumber": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Serialnumber"
          },
          "algorithm": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Algorithm"
          },
          "issuer": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Issuer"
          },
          "sealedAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Sealedat"
          },
          "policyOid": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Policyoid"
          },
          "tsaName": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Tsaname"
          },
          "environment": {
            "type": "string",
            "title": "Environment"
          },
          "sandbox": {
            "type": "boolean",
            "title": "Sandbox"
          },
          "downloadUrl": {
            "type": "string",
            "title": "Downloadurl"
          },
          "downloadUrlExpiresAt": {
            "type": "string",
            "format": "date-time",
            "title": "Downloadurlexpiresat"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "title": "Createdat"
          }
        },
        "type": "object",
        "required": [
          "livemode",
          "id",
          "hashSha256",
          "externalId",
          "label",
          "constancia",
          "constanciaSha256",
          "serialNumber",
          "algorithm",
          "issuer",
          "sealedAt",
          "policyOid",
          "tsaName",
          "environment",
          "sandbox",
          "downloadUrl",
          "downloadUrlExpiresAt",
          "createdAt"
        ],
        "title": "ConstanciaResponse"
      },
      "Document": {
        "properties": {
          "livemode": {
            "type": "boolean",
            "title": "Livemode",
            "description": "`true` en entorno `live`, `false` en `test`/`dev` (marca de agua, sin validez legal)."
          },
          "id": {
            "type": "string",
            "title": "Id",
            "description": "ID del documento (`doc_…`)."
          },
          "object": {
            "type": "string",
            "const": "document",
            "title": "Object",
            "description": "Siempre `\"document\"`.",
            "default": "document"
          },
          "name": {
            "type": "string",
            "title": "Name",
            "description": "Nombre visible del documento."
          },
          "status": {
            "$ref": "#/components/schemas/DocumentStatus",
            "description": "Estado del ciclo de vida: `draft`, `collecting_data`, `awaiting_signatures`, `correcting`, `processing`, `completed`, `expired`, `voided`, `error`."
          },
          "documentType": {
            "type": "string",
            "title": "Documenttype",
            "description": "Token opaco del tipo de documento."
          },
          "signerCount": {
            "type": "integer",
            "title": "Signercount",
            "description": "Número total de firmantes."
          },
          "signedCount": {
            "type": "integer",
            "title": "Signedcount",
            "description": "Cuántos firmantes ya firmaron."
          },
          "ownerId": {
            "type": "string",
            "title": "Ownerid",
            "description": "Dueño del documento (`usr_…`)."
          },
          "orgId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Orgid",
            "description": "Organización del documento (`org_…`)."
          },
          "folderId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Folderid",
            "description": "Carpeta que contiene el documento (`fld_…`)."
          },
          "expiresAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Expiresat",
            "description": "Fecha límite de firma (ISO 8601)."
          },
          "expirationReminders": {
            "anyOf": [
              {
                "items": {
                  "type": "integer"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Expirationreminders",
            "description": "Horas antes del vencimiento en las que se envían recordatorios."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "title": "Createdat",
            "description": "Fecha de creación (ISO 8601)."
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "title": "Updatedat",
            "description": "Última actualización (ISO 8601)."
          }
        },
        "type": "object",
        "required": [
          "livemode",
          "id",
          "name",
          "status",
          "documentType",
          "signerCount",
          "signedCount",
          "ownerId",
          "createdAt",
          "updatedAt"
        ],
        "title": "Document",
        "description": "A document resource object. Inherits ``livemode`` from V3ResponseSchema."
      },
      "DocumentCreateRequest": {
        "properties": {
          "source": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/DocumentSource"
              },
              {
                "type": "null"
              }
            ],
            "description": "Discriminador de fuente: `template` o `file`. Opcional (se infiere), pero si lo mandas debe concordar con el campo presente."
          },
          "templateId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Templateid",
            "description": "ID de una plantilla existente (`tmpl_…`). Requerido cuando `source` es `template`."
          },
          "templateValues": {
            "anyOf": [
              {
                "additionalProperties": {
                  "type": "string"
                },
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Templatevalues",
            "description": "Mapa de valores para las variables de la plantilla, con llaves naturales del negocio (ej. `nombre_completo`). Nunca se camelizan."
          },
          "file": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/FileInput"
              },
              {
                "type": "null"
              }
            ],
            "description": "Archivo inline cuando `source` es `file`. Mutuamente exclusivo con `templateId`."
          },
          "name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Name",
            "description": "Nombre visible del documento. Si se omite, se deriva de la plantilla o del archivo."
          },
          "signers": {
            "anyOf": [
              {
                "items": {
                  "$ref": "#/components/schemas/SignerCreate"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Signers",
            "description": "Firmantes a adjuntar al crear el documento."
          },
          "signatureValidation": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/SignatureValidationConfig"
              },
              {
                "type": "null"
              }
            ],
            "description": "Nivel de validez legal (autógrafa/NOM-151/FEA/biometría/videofirma). Por default: solo autógrafa."
          },
          "expiresAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Expiresat",
            "description": "Fecha límite de firma (ISO 8601)."
          }
        },
        "type": "object",
        "title": "DocumentCreateRequest",
        "description": "Create a document from a template **or** an inline file (exactly one).\n\n``template_values`` is a **map keyed by variable name** (natural snake keys,\ne.g. ``{\"nombre_completo\": \"Juan\"}``) — user data, never camelized."
      },
      "DocumentEvidence": {
        "properties": {
          "livemode": {
            "type": "boolean",
            "title": "Livemode",
            "description": "`true` en entorno `live`, `false` en `test`/`dev` (marca de agua, sin validez legal)."
          },
          "documentId": {
            "type": "string",
            "title": "Documentid",
            "description": "ID del documento (`doc_…`)."
          },
          "available": {
            "type": "boolean",
            "title": "Available",
            "description": "`true` una vez que todos los firmantes completaron."
          },
          "evidencePdf": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/EvidenceFile"
              },
              {
                "type": "null"
              }
            ],
            "description": "PDF sellado con todas las firmas y la bitácora de auditoría."
          },
          "nom151": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/EvidenceFile"
              },
              {
                "type": "null"
              }
            ],
            "description": "Constancia de conservación NOM-151 (timestamp + cadena de hash). `null` si el documento no es `livemode`."
          }
        },
        "type": "object",
        "required": [
          "livemode",
          "documentId",
          "available"
        ],
        "title": "DocumentEvidence",
        "description": "Evidence bundle for a completed document. Both files are `null` until every\nsigner has finished — poll `available`."
      },
      "DocumentList": {
        "properties": {
          "object": {
            "type": "string",
            "const": "list",
            "title": "Object",
            "description": "Siempre `\"list\"`.",
            "default": "list"
          },
          "data": {
            "items": {
              "$ref": "#/components/schemas/Document"
            },
            "type": "array",
            "title": "Data",
            "description": "Arreglo de objetos Document."
          },
          "hasMore": {
            "type": "boolean",
            "title": "Hasmore",
            "description": "`true` si hay más resultados después de esta página."
          },
          "nextCursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Nextcursor",
            "description": "Cursor para la siguiente página (pásalo como `startingAfter`)."
          },
          "previousCursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Previouscursor",
            "description": "Cursor para la página anterior (pásalo como `endingBefore`)."
          },
          "limit": {
            "type": "integer",
            "title": "Limit",
            "description": "El límite aplicado a esta página."
          },
          "totalCount": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Totalcount",
            "description": "Total de coincidencias. Solo se llena cuando pides `includeTotal=true`."
          }
        },
        "type": "object",
        "required": [
          "data",
          "hasMore",
          "limit"
        ],
        "title": "DocumentList",
        "description": "Cursor-paginated envelope. Deliberately NOT a resource object (no\n``livemode``): it is the pagination wrapper, reused verbatim by W4."
      },
      "DocumentScopeEnum": {
        "type": "string",
        "enum": [
          "owner",
          "org",
          "tenant",
          "accessible"
        ],
        "title": "DocumentScopeEnum",
        "description": "Document scope for filtering.\n\nDefines the scope of documents to retrieve:\n- OWNER: Only documents where user is the creator (default)\n- ORG: All documents in user's organization\n- TENANT: All documents in user's tenant (multi-org admin scope)\n- ACCESSIBLE: All documents where user is owner OR participant"
      },
      "DocumentSort": {
        "type": "string",
        "enum": [
          "createdAt",
          "-createdAt",
          "updatedAt",
          "-updatedAt"
        ],
        "title": "DocumentSort",
        "description": "``?sort=`` whitelist for ``GET /documents``.\n\nRestricted to ``createdAt``/``updatedAt`` (asc, or a ``-`` prefix for desc).\n``name`` and ``documentType`` are **not** sortable: the cursor encodes the sort\nvalue as an ISO ``datetime``. A value outside this enum is a 422\n``VALIDATION_ERROR`` at the query boundary."
      },
      "DocumentSource": {
        "type": "string",
        "enum": [
          "template",
          "file"
        ],
        "title": "DocumentSource",
        "description": "Explicit discriminator for ``POST /documents``.\n\nOptional: if omitted, the source is inferred from which of\n``templateId``/``file`` is present — but if given, it must agree with the\nfield actually supplied."
      },
      "DocumentStats": {
        "properties": {
          "totalDocuments": {
            "type": "integer",
            "title": "Totaldocuments",
            "description": "Total de documentos en el scope pedido."
          },
          "totalCompleted": {
            "type": "integer",
            "title": "Totalcompleted",
            "description": "Documentos con flujo de firma completado."
          },
          "totalPending": {
            "type": "integer",
            "title": "Totalpending",
            "description": "Documentos esperando firma o en proceso."
          },
          "totalConfiguring": {
            "type": "integer",
            "title": "Totalconfiguring",
            "description": "Documentos en configuración, antes de enviarse."
          },
          "totalError": {
            "type": "integer",
            "title": "Totalerror",
            "description": "Documentos cuyo estado de firma es `error` — algo falló procesándolos después de enviarse. No están incluidos en `totalPending`."
          },
          "recentCount": {
            "type": "integer",
            "title": "Recentcount",
            "description": "Documentos creados en los últimos 7 días."
          }
        },
        "type": "object",
        "required": [
          "totalDocuments",
          "totalCompleted",
          "totalPending",
          "totalConfiguring",
          "totalError",
          "recentCount"
        ],
        "title": "DocumentStats",
        "description": "Aggregate counts. Not a resource object (no `livemode`) — mirrors\n`DocumentList`'s envelope treatment."
      },
      "DocumentStatus": {
        "type": "string",
        "enum": [
          "draft",
          "collecting_data",
          "awaiting_signatures",
          "correcting",
          "processing",
          "completed",
          "expired",
          "voided",
          "error"
        ],
        "title": "DocumentStatus",
        "description": "Public document lifecycle status (maps from internal SCREAMING states).\n\nNamespace = ``snake_underscore`` data tokens (distinct from the dotted\n``resource.pastTense`` event namespace). See ``mappers.py`` for the\ninternal↔public map.\n\nOpen enum: clients MUST tolerate values not in this list.",
        "x-extensible-enum": true
      },
      "DocumentUpdateRequest": {
        "properties": {
          "name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Name",
            "description": "Nuevo nombre visible del documento."
          },
          "folderId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Folderid",
            "description": "Mover a otra carpeta (`fld_…`), o `null` para sacarlo de la carpeta."
          }
        },
        "additionalProperties": false,
        "type": "object",
        "title": "DocumentUpdateRequest",
        "description": "PATCH body — only ``name`` and ``folderId`` are mutable.\n\n``extra=\"forbid\"`` (merged onto the camel config): any other field\n(``status``, ``ownerId``, ``id``, ``createdAt``, …) is a 422\n``VALIDATION_ERROR`` naming the offending field."
      },
      "Event": {
        "properties": {
          "livemode": {
            "type": "boolean",
            "title": "Livemode",
            "description": "`true` en entorno `live`, `false` en `test`/`dev` (marca de agua, sin validez legal)."
          },
          "id": {
            "type": "string",
            "title": "Id",
            "description": "ID del evento (`evt_…`)."
          },
          "object": {
            "type": "string",
            "const": "event",
            "title": "Object",
            "description": "Siempre `\"event\"`.",
            "default": "event"
          },
          "type": {
            "type": "string",
            "title": "Type",
            "description": "Tipo de evento (ej. `document.created`, `signer.signed`)."
          },
          "documentId": {
            "type": "string",
            "title": "Documentid",
            "description": "Documento asociado (`doc_…`)."
          },
          "success": {
            "type": "boolean",
            "title": "Success",
            "description": "Si el evento fue exitoso."
          },
          "message": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Message",
            "description": "Mensaje legible del evento."
          },
          "actorType": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Actortype",
            "description": "Tipo de actor que originó el evento."
          },
          "signatureId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Signatureid",
            "description": "Firma asociada (`sgr_…`), si aplica."
          },
          "data": {
            "additionalProperties": true,
            "type": "object",
            "title": "Data",
            "description": "Payload del evento. Solo las llaves de primer nivel se camelizan; los datos anidados quedan intactos."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "title": "Createdat",
            "description": "Momento del evento (ISO 8601)."
          }
        },
        "type": "object",
        "required": [
          "livemode",
          "id",
          "type",
          "documentId",
          "success",
          "createdAt"
        ],
        "title": "Event",
        "description": "A document event resource object. Inherits ``livemode``.\n\n``type`` is an opaque token from the ``DocumentEventType`` catalog\n(``document.created`` — dotted ``resource.pastTense`` namespace), passed\nthrough as data. ``data`` is the event's JSONB payload; only its **top-level**\nkeys are camelized so a snake key (``signer_email``) never leaks at the\nsurface, while nested user data is left byte-for-byte intact."
      },
      "EventList": {
        "properties": {
          "object": {
            "type": "string",
            "const": "list",
            "title": "Object",
            "description": "Siempre `\"list\"`.",
            "default": "list"
          },
          "data": {
            "items": {
              "$ref": "#/components/schemas/Event"
            },
            "type": "array",
            "title": "Data",
            "description": "Arreglo de eventos del documento, más recientes primero."
          },
          "hasMore": {
            "type": "boolean",
            "title": "Hasmore",
            "description": "`true` si hay más eventos después de esta página."
          },
          "nextCursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Nextcursor",
            "description": "Cursor para la siguiente página (pásalo como `startingAfter`)."
          },
          "previousCursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Previouscursor",
            "description": "Cursor para la página anterior (pásalo como `endingBefore`)."
          },
          "limit": {
            "type": "integer",
            "title": "Limit",
            "description": "El límite aplicado a esta página."
          }
        },
        "type": "object",
        "required": [
          "data",
          "hasMore",
          "limit"
        ],
        "title": "EventList",
        "description": "Cursor-paginated envelope for events (same shape as DocumentList)."
      },
      "EvidenceFile": {
        "properties": {
          "url": {
            "type": "string",
            "title": "Url",
            "description": "URL firmada para descargar el archivo (vigente 24 horas)."
          },
          "sha256": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Sha256",
            "description": "Hash SHA-256 del archivo, si ya se calculó."
          }
        },
        "type": "object",
        "required": [
          "url"
        ],
        "title": "EvidenceFile",
        "description": "A downloadable evidence artifact — presigned, short-lived."
      },
      "FileInput": {
        "properties": {
          "content": {
            "type": "string",
            "title": "Content",
            "description": "Contenido del archivo codificado en Base64. Máximo 10 MB decodificados."
          },
          "fileType": {
            "type": "string",
            "title": "Filetype",
            "description": "Tipo de archivo. Default `pdf`.",
            "default": "pdf"
          },
          "name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Name",
            "description": "Nombre del archivo (ej. `contrato.pdf`). Se valida contra path traversal."
          }
        },
        "type": "object",
        "required": [
          "content"
        ],
        "title": "FileInput",
        "description": "Inline file source for ``POST /documents`` (base64 PDF, ``source=file``).\n\n``content`` is a base64-encoded PDF, capped at 10 MB **decoded** (413\n``DOCUMENT_TOO_LARGE``). ``name`` is path-checked: a value containing ``..``\nor a path separator is a 400 ``INVALID_ID``. Both run before the file is\nstored."
      },
      "Folder": {
        "properties": {
          "livemode": {
            "type": "boolean",
            "title": "Livemode",
            "description": "`true` en entorno `live`, `false` en `test`/`dev` (marca de agua, sin validez legal)."
          },
          "id": {
            "type": "string",
            "title": "Id",
            "description": "ID de la carpeta (`fld_…`)."
          },
          "object": {
            "type": "string",
            "const": "folder",
            "title": "Object",
            "description": "Siempre `\"folder\"`.",
            "default": "folder"
          },
          "name": {
            "type": "string",
            "title": "Name",
            "description": "Nombre de la carpeta."
          },
          "ownerId": {
            "type": "string",
            "title": "Ownerid",
            "description": "Dueño de la carpeta (`usr_…`)."
          },
          "parentId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Parentid",
            "description": "Carpeta padre (`fld_…`), o `null` si está en la raíz."
          },
          "hasDocs": {
            "type": "boolean",
            "title": "Hasdocs",
            "description": "Si la carpeta contiene al menos un documento."
          },
          "isMain": {
            "type": "boolean",
            "title": "Ismain",
            "description": "Si es la carpeta principal (raíz) del usuario."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "title": "Createdat",
            "description": "Fecha de creación (ISO 8601)."
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "title": "Updatedat",
            "description": "Última actualización (ISO 8601)."
          }
        },
        "type": "object",
        "required": [
          "livemode",
          "id",
          "name",
          "ownerId",
          "hasDocs",
          "isMain",
          "createdAt",
          "updatedAt"
        ],
        "title": "Folder",
        "description": "A folder resource object. Inherits ``livemode`` from V3ResponseSchema.\n\nReused for list items, ``GET /folders/{id}``, ``POST /folders`` and\n``PATCH /folders/{id}`` (same pattern as ``Template``)."
      },
      "FolderCreateRequest": {
        "properties": {
          "name": {
            "type": "string",
            "title": "Name",
            "description": "Nombre de la carpeta."
          },
          "parentId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Parentid",
            "description": "Carpeta padre (`fld_…`) para anidar. `null` u omitido = nivel raíz."
          }
        },
        "type": "object",
        "required": [
          "name"
        ],
        "title": "FolderCreateRequest",
        "description": "``POST /folders`` body. ``parentId``, when given, must be a ``fld_``\nprefixed id (400 ``INVALID_ID`` on a malformed one) — ``null``/omitted\nmeans root level."
      },
      "FolderList": {
        "properties": {
          "object": {
            "type": "string",
            "const": "list",
            "title": "Object",
            "description": "Siempre `\"list\"`.",
            "default": "list"
          },
          "data": {
            "items": {
              "$ref": "#/components/schemas/Folder"
            },
            "type": "array",
            "title": "Data",
            "description": "Arreglo de objetos Folder."
          },
          "hasMore": {
            "type": "boolean",
            "title": "Hasmore",
            "description": "`true` si hay más resultados después de esta página."
          },
          "nextCursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Nextcursor",
            "description": "Cursor para la siguiente página (pásalo como `startingAfter`)."
          },
          "previousCursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Previouscursor",
            "description": "Cursor para la página anterior (pásalo como `endingBefore`)."
          },
          "limit": {
            "type": "integer",
            "title": "Limit",
            "description": "El límite aplicado a esta página."
          }
        },
        "type": "object",
        "required": [
          "data",
          "hasMore",
          "limit"
        ],
        "title": "FolderList",
        "description": "Cursor-paginated envelope. Deliberately NOT a resource object (no\n``livemode``) — the pagination wrapper, same frozen shape as\n``DocumentList``/``TemplateList``/``EventList``."
      },
      "FolderSort": {
        "type": "string",
        "enum": [
          "createdAt",
          "-createdAt"
        ],
        "title": "FolderSort",
        "description": "``?sort=`` whitelist for ``GET /folders`` — same shape as\n``TemplateSort``/``DocumentSort`` (the reused cursor codec serializes the\nsort value as an ISO ``datetime``)."
      },
      "FolderUpdateRequest": {
        "properties": {
          "name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Name",
            "description": "Nuevo nombre de la carpeta."
          },
          "parentId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Parentid",
            "description": "Mover bajo otra carpeta (`fld_…`), o `null` para llevarla a la raíz."
          }
        },
        "additionalProperties": false,
        "type": "object",
        "title": "FolderUpdateRequest",
        "description": "PATCH body — only ``name``/``parentId`` are mutable.\n\n``extra=\"forbid\"`` (merged onto the camel config): any other field is a\n422 ``VALIDATION_ERROR`` naming the offending field — the \"patch an\nimmutable field\" rejection (same pattern as ``DocumentUpdateRequest``)."
      },
      "FunnelList": {
        "properties": {
          "object": {
            "type": "string",
            "const": "list",
            "title": "Object",
            "description": "Siempre `\"list\"`.",
            "default": "list"
          },
          "data": {
            "items": {
              "$ref": "#/components/schemas/FunnelStep"
            },
            "type": "array",
            "title": "Data",
            "description": "Las 4 etapas del embudo, en orden."
          },
          "hasMore": {
            "type": "boolean",
            "title": "Hasmore",
            "description": "Siempre `false` — colección acotada, sin cursor.",
            "default": false
          },
          "nextCursor": {
            "type": "null",
            "title": "Nextcursor",
            "description": "Siempre `null` — esta colección no pagina."
          },
          "previousCursor": {
            "type": "null",
            "title": "Previouscursor",
            "description": "Siempre `null` — esta colección no pagina."
          },
          "limit": {
            "type": "null",
            "title": "Limit",
            "description": "Siempre `null` — sin parámetro `limit` en este endpoint."
          }
        },
        "type": "object",
        "required": [
          "data"
        ],
        "title": "FunnelList",
        "description": "Bounded, non-paginated collection — the funnel always has exactly 4\nstages. Carries the same envelope keys as a cursor-paginated list (always\n``null`` here) so an SDK can use one generic list-response type (F1.6)."
      },
      "FunnelStep": {
        "properties": {
          "label": {
            "type": "string",
            "title": "Label",
            "description": "Nombre de la etapa (ej. \"Enviados\")."
          },
          "count": {
            "type": "integer",
            "title": "Count",
            "description": "Documentos en esa etapa."
          },
          "pct": {
            "type": "number",
            "title": "Pct",
            "description": "Porcentaje de esa etapa respecto a la primera."
          }
        },
        "type": "object",
        "required": [
          "label",
          "count",
          "pct"
        ],
        "title": "FunnelStep",
        "description": "One stage in the signing funnel (Enviados / En progreso / Completados /\nExpirados)."
      },
      "HTTPValidationError": {
        "properties": {
          "detail": {
            "items": {
              "$ref": "#/components/schemas/ValidationError"
            },
            "type": "array",
            "title": "Detail"
          }
        },
        "type": "object",
        "title": "HTTPValidationError"
      },
      "HealthzResponse": {
        "properties": {
          "status": {
            "type": "string",
            "title": "Status",
            "description": "Siempre `\"ok\"` cuando la API responde."
          },
          "apiVersion": {
            "type": "string",
            "title": "Apiversion",
            "description": "Versión fechada del contrato v3 (idioma Stripe-Version)."
          },
          "requestId": {
            "type": "string",
            "title": "Requestid",
            "description": "El mismo id de correlación que trae el header `AllSign-Request-Id`."
          }
        },
        "type": "object",
        "required": [
          "status",
          "apiVersion",
          "requestId"
        ],
        "title": "HealthzResponse",
        "description": "Liveness payload — proves the camelCase pipeline end-to-end.\n\n``api_version`` and ``request_id`` become ``apiVersion`` / ``requestId`` on\nthe wire via the v3 alias generator."
      },
      "MonthlyTrendPoint": {
        "properties": {
          "month": {
            "type": "string",
            "title": "Month",
            "description": "Abreviatura del mes en inglés, sin año (ej. \"Jan\"). No es formato ISO `YYYY-MM`: el mismo valor se repite para meses de distintos años. Mantiene el formato que ya expone `GET /v2/analytics/trend` (contrato público en vivo) por compatibilidad."
          },
          "signed": {
            "type": "integer",
            "title": "Signed",
            "description": "Documentos firmados ese mes."
          },
          "avgHours": {
            "type": "number",
            "title": "Avghours",
            "description": "Horas promedio de firma ese mes."
          }
        },
        "type": "object",
        "required": [
          "month",
          "signed",
          "avgHours"
        ],
        "title": "MonthlyTrendPoint",
        "description": "Signed documents and average signing hours for one month."
      },
      "RecentEvent": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id",
            "description": "ID del evento (`evt_…`)."
          },
          "documentName": {
            "type": "string",
            "title": "Documentname",
            "description": "Nombre del documento del evento."
          },
          "eventType": {
            "type": "string",
            "title": "Eventtype",
            "description": "Tipo de evento (token opaco, ej. `document.created`)."
          },
          "actorName": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Actorname",
            "description": "Nombre de quien originó el evento, o `null` si fue el sistema."
          },
          "actorInitials": {
            "type": "string",
            "title": "Actorinitials",
            "description": "Iniciales del actor."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "title": "Createdat",
            "description": "Cuándo ocurrió (ISO 8601)."
          }
        },
        "type": "object",
        "required": [
          "id",
          "documentName",
          "eventType",
          "actorInitials",
          "createdAt"
        ],
        "title": "RecentEvent",
        "description": "A recent document event for the tenant activity feed.\n\n``id`` is the underlying ``document.document_event`` row id, encoded with\nthe same ``evt_`` prefix ``GET /v3/documents/{id}/events`` uses (id\nopacity holds regardless of which route surfaces the row)."
      },
      "RecentEventList": {
        "properties": {
          "object": {
            "type": "string",
            "const": "list",
            "title": "Object",
            "description": "Siempre `\"list\"`.",
            "default": "list"
          },
          "data": {
            "items": {
              "$ref": "#/components/schemas/RecentEvent"
            },
            "type": "array",
            "title": "Data",
            "description": "Eventos recientes, más nuevos primero."
          },
          "hasMore": {
            "type": "boolean",
            "title": "Hasmore",
            "description": "Siempre `false` — la lista la acota `limit`.",
            "default": false
          },
          "nextCursor": {
            "type": "null",
            "title": "Nextcursor",
            "description": "Siempre `null` — esta colección no pagina."
          },
          "previousCursor": {
            "type": "null",
            "title": "Previouscursor",
            "description": "Siempre `null` — esta colección no pagina."
          },
          "limit": {
            "type": "integer",
            "title": "Limit",
            "description": "El límite aplicado a esta respuesta."
          }
        },
        "type": "object",
        "required": [
          "data",
          "limit"
        ],
        "title": "RecentEventList",
        "description": "Bounded, non-paginated collection — ``?limit=`` bounded (default 8, max 50).\nSame envelope keys as a cursor-paginated list (F1.6): unlike the fully-fixed\ncollections, ``limit`` here echoes the actual applied value, not ``null``."
      },
      "Recipient": {
        "properties": {
          "email": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Email",
            "description": "Correo del destinatario."
          },
          "phone": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Phone",
            "description": "Teléfono del destinatario (invitación por WhatsApp)."
          },
          "name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Name",
            "description": "Nombre del destinatario."
          }
        },
        "type": "object",
        "title": "Recipient",
        "description": "A send recipient — at least one of email/phone."
      },
      "RemindResponse": {
        "properties": {
          "documentId": {
            "type": "string",
            "title": "Documentid",
            "description": "ID del documento (`doc_…`)."
          },
          "signerId": {
            "type": "string",
            "title": "Signerid",
            "description": "ID del firmante recordado (`sgr_…`)."
          },
          "sentAt": {
            "type": "string",
            "format": "date-time",
            "title": "Sentat",
            "description": "Cuándo se procesó el recordatorio."
          },
          "nextAllowedAt": {
            "type": "string",
            "format": "date-time",
            "title": "Nextallowedat",
            "description": "Antes de esta fecha, un nuevo recordatorio a este firmante responde 429."
          },
          "channel": {
            "type": "string",
            "title": "Channel",
            "description": "Canal de entrega: `email` o `whatsapp`."
          },
          "delivered": {
            "type": "boolean",
            "title": "Delivered",
            "description": "`true` si el envío tuvo éxito. `false` no falla la petición — el remitente puede reintentar."
          }
        },
        "type": "object",
        "required": [
          "documentId",
          "signerId",
          "sentAt",
          "nextAllowedAt",
          "channel",
          "delivered"
        ],
        "title": "RemindResponse",
        "description": "Confirms a manual reminder attempt. Not a resource object (no\n`livemode`) — an action confirmation, not something you `GET` back."
      },
      "SendRequest": {
        "properties": {
          "recipients": {
            "anyOf": [
              {
                "items": {
                  "$ref": "#/components/schemas/Recipient"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Recipients",
            "description": "Destinatarios de la invitación. Si se omite, se usan los firmantes ya adjuntos al documento."
          }
        },
        "type": "object",
        "title": "SendRequest"
      },
      "SignatureValidationConfig": {
        "properties": {
          "autografa": {
            "type": "boolean",
            "title": "Autografa",
            "description": "Firma autógrafa (trazo en pantalla).",
            "default": true
          },
          "nom151": {
            "type": "boolean",
            "title": "Nom151",
            "description": "Constancia de conservación NOM-151.",
            "default": false
          },
          "fea": {
            "type": "boolean",
            "title": "Fea",
            "description": "Firma Electrónica Avanzada (FEA/e.firma SAT).",
            "default": false
          },
          "biometricSignature": {
            "type": "boolean",
            "title": "Biometricsignature",
            "description": "Verificación biométrica (selfie vs. identificación, anti-deepfake).",
            "default": false
          },
          "idScan": {
            "type": "boolean",
            "title": "Idscan",
            "description": "Escaneo de identificación oficial (INE, pasaporte).",
            "default": false
          },
          "videofirma": {
            "type": "boolean",
            "title": "Videofirma",
            "description": "Graba video del firmante durante el proceso de firma.",
            "default": false
          }
        },
        "type": "object",
        "title": "SignatureValidationConfig",
        "description": "Nivel de validez legal del documento (subset curado — v2 tiene más flags\ninternos de la pipeline de verificación de identidad; estos 6 son los\nniveles de producto: autógrafa simple, NOM-151, FEA, biometría/anti-deepfake,\nescaneo de identificación, y video de firma)."
      },
      "Signer": {
        "properties": {
          "livemode": {
            "type": "boolean",
            "title": "Livemode",
            "description": "`true` en entorno `live`, `false` en `test`/`dev` (marca de agua, sin validez legal)."
          },
          "id": {
            "type": "string",
            "title": "Id",
            "description": "ID del firmante (`sgr_…`)."
          },
          "object": {
            "type": "string",
            "const": "signer",
            "title": "Object",
            "description": "Siempre `\"signer\"`.",
            "default": "signer"
          },
          "documentId": {
            "type": "string",
            "title": "Documentid",
            "description": "Documento al que pertenece (`doc_…`)."
          },
          "email": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Email",
            "description": "Correo del firmante."
          },
          "phone": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Phone",
            "description": "Teléfono del firmante."
          },
          "name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Name",
            "description": "Nombre del firmante."
          },
          "status": {
            "$ref": "#/components/schemas/SignerStatus",
            "description": "Estado por firmante: `pending`, `sent`, `signed`, `cancelled`."
          },
          "signedAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Signedat",
            "description": "Momento de la firma (ISO 8601), o `null` si aún no firma."
          }
        },
        "type": "object",
        "required": [
          "livemode",
          "id",
          "documentId",
          "status"
        ],
        "title": "Signer",
        "description": "A signer resource object. Inherits ``livemode`` from V3ResponseSchema."
      },
      "SignerCreate": {
        "properties": {
          "email": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Email",
            "description": "Correo del firmante."
          },
          "phone": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Phone",
            "description": "Teléfono del firmante (para invitación por WhatsApp)."
          },
          "name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Name",
            "description": "Nombre del firmante."
          },
          "roleName": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 255
              },
              {
                "type": "null"
              }
            ],
            "title": "Rolename",
            "description": "Rol semántico del firmante (ej. `proveedor`), usado para auto-asignar variables de plantilla marcadas con ese rol. Opcional — si se omite, las variables deben asignarse manualmente."
          }
        },
        "type": "object",
        "title": "SignerCreate",
        "description": "A signer to attach at create time (email or phone)."
      },
      "SignerList": {
        "properties": {
          "object": {
            "type": "string",
            "const": "list",
            "title": "Object",
            "description": "Siempre `\"list\"`.",
            "default": "list"
          },
          "data": {
            "items": {
              "$ref": "#/components/schemas/Signer"
            },
            "type": "array",
            "title": "Data",
            "description": "Arreglo de firmantes del documento."
          },
          "hasMore": {
            "type": "boolean",
            "title": "Hasmore",
            "description": "Siempre `false` en esta colección acotada.",
            "default": false
          },
          "nextCursor": {
            "type": "null",
            "title": "Nextcursor",
            "description": "Siempre `null` — esta colección no pagina."
          },
          "previousCursor": {
            "type": "null",
            "title": "Previouscursor",
            "description": "Siempre `null` — esta colección no pagina."
          },
          "limit": {
            "type": "null",
            "title": "Limit",
            "description": "Siempre `null` — sin parámetro `limit` en este endpoint."
          }
        },
        "type": "object",
        "required": [
          "data"
        ],
        "title": "SignerList",
        "description": "Bounded (≤250), non-paginated collection.\n\nCarries the SAME envelope keys as a cursor-paginated list (``nextCursor``/\n``previousCursor``/``limit``, always ``null`` here) so an SDK can use one\ngeneric list-response type across every v3 endpoint — a client that reads\n``.nextCursor`` on a bounded collection gets ``null``, never ``undefined``."
      },
      "SignerStatus": {
        "type": "string",
        "enum": [
          "pending",
          "sent",
          "signed",
          "cancelled"
        ],
        "title": "SignerStatus",
        "description": "Public per-signer status (maps from internal Signature.status strings).\n\nOpen enum: clients MUST tolerate values not in this list.",
        "x-extensible-enum": true
      },
      "SigningSession": {
        "properties": {
          "livemode": {
            "type": "boolean",
            "title": "Livemode",
            "description": "`true` en entorno `live`, `false` en `test`/`dev` (marca de agua, sin validez legal)."
          },
          "id": {
            "type": "string",
            "title": "Id",
            "description": "ID de la sesión (`ses_…`)."
          },
          "object": {
            "type": "string",
            "title": "Object",
            "description": "Siempre `\"signing_session\"`.",
            "default": "signing_session"
          },
          "status": {
            "$ref": "#/components/schemas/SigningSessionStatus",
            "description": "Estado de la sesión: `pending`, `active`, `completed`, `expired` o `cancelled`."
          },
          "clientSecret": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Clientsecret",
            "description": "El secreto que tu frontend pasa al iframe. Devuelto una sola vez — en el GET viene `null`."
          },
          "document": {
            "$ref": "#/components/schemas/SigningSessionDocument",
            "description": "Documento que firma la sesión."
          },
          "signer": {
            "$ref": "#/components/schemas/SigningSessionSigner",
            "description": "Firmante ligado a la sesión."
          },
          "expiresAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Expiresat",
            "description": "Cuándo expira la sesión (ISO 8601)."
          },
          "createdAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Createdat",
            "description": "Cuándo se creó (ISO 8601)."
          },
          "mountedAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Mountedat",
            "description": "Cuándo se montó el iframe por primera vez."
          },
          "completedAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Completedat",
            "description": "Cuándo se completó la firma."
          },
          "signature": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/SigningSessionSignature"
              },
              {
                "type": "null"
              }
            ],
            "description": "Estado autoritativo de la firma."
          },
          "evidence": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/SigningSessionEvidence"
              },
              {
                "type": "null"
              }
            ],
            "description": "Paquete de evidencia sellada. Solo con `?expand=evidence`."
          }
        },
        "type": "object",
        "required": [
          "livemode",
          "id",
          "status",
          "document",
          "signer"
        ],
        "title": "SigningSession",
        "description": "An embedded signing-session resource. Inherits ``livemode``.\n\n``clientSecret`` is populated ONLY on the create response (returned once);\n``createdAt``/``mountedAt``/``completedAt``/``signature``/``evidence`` are\npopulated on the GET (``evidence`` only when expanded)."
      },
      "SigningSessionCreateRequest": {
        "properties": {
          "documentId": {
            "type": "string",
            "title": "Documentid",
            "description": "ID del documento a firmar (`doc_…`). Debe existir y tener al firmante como participante."
          },
          "signerEmail": {
            "type": "string",
            "title": "Signeremail",
            "description": "Correo del participante que firmará en el iframe."
          },
          "successUrl": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Successurl",
            "description": "A dónde redirigir cuando la firma se completa."
          },
          "cancelUrl": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Cancelurl",
            "description": "A dónde redirigir si el firmante cancela."
          },
          "brandProfileId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Brandprofileid",
            "description": "Perfil de marca (white-label) para el iframe."
          },
          "allowedOrigins": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Allowedorigins",
            "description": "Orígenes donde puede montarse el iframe. Obligatorio para keys `live`."
          },
          "otpMode": {
            "$ref": "#/components/schemas/SigningSessionOtpMode",
            "description": "Verificación de identidad al crear: `none` (default), `required` o `integrator_verified`. Solo `none` está implementado.",
            "default": "none"
          }
        },
        "type": "object",
        "required": [
          "documentId",
          "signerEmail"
        ],
        "title": "SigningSessionCreateRequest",
        "description": "Create an embedded signing session for a signer of an existing document.\n\n``testMode`` is deliberately ABSENT (Red-team R5): ``livemode`` is derived\nfrom the API key's ``environment``, never a client flag, so a ``test`` key\ncan never mint a \"live\" (legally binding) session or vice versa."
      },
      "SigningSessionDocument": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id",
            "description": "ID del documento (`doc_…`)."
          },
          "title": {
            "type": "string",
            "title": "Title",
            "description": "Nombre del documento."
          }
        },
        "type": "object",
        "required": [
          "id",
          "title"
        ],
        "title": "SigningSessionDocument",
        "description": "The document a session signs (id is ``doc_`` prefixed)."
      },
      "SigningSessionEvidence": {
        "properties": {
          "available": {
            "type": "boolean",
            "title": "Available",
            "description": "Si el paquete de evidencia ya está listo."
          },
          "evidencePdf": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/SigningSessionEvidencePdf"
              },
              {
                "type": "null"
              }
            ],
            "description": "Puntero al PDF de evidencia sellado."
          },
          "nom151": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/SigningSessionNom151"
              },
              {
                "type": "null"
              }
            ],
            "description": "Puntero a la constancia NOM-151."
          }
        },
        "type": "object",
        "required": [
          "available"
        ],
        "title": "SigningSessionEvidence",
        "description": "Expandable evidence bundle (``?expand=evidence`` on the GET).\n\n``available`` is true only when every signer finished AND the Temporal\nworkflow has written the evidence PDF to S3; until then both pointers are\nnull and the integrator should poll again."
      },
      "SigningSessionEvidencePdf": {
        "properties": {
          "s3Key": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "S3Key",
            "description": "Ruta S3 del PDF de evidencia."
          },
          "presignedUrl": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Presignedurl",
            "description": "URL prefirmada del PDF de evidencia (válida ~24 h)."
          },
          "hash": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Hash",
            "description": "Hash del PDF de evidencia."
          }
        },
        "type": "object",
        "title": "SigningSessionEvidencePdf",
        "description": "Signed evidence PDF pointer (present only once the document is sealed)."
      },
      "SigningSessionInit": {
        "properties": {
          "livemode": {
            "type": "boolean",
            "title": "Livemode",
            "description": "`true` en entorno `live`, `false` en `test`/`dev` (marca de agua, sin validez legal)."
          },
          "sessionId": {
            "type": "string",
            "title": "Sessionid",
            "description": "ID de la sesión (`ses_…`)."
          },
          "signatureId": {
            "type": "string",
            "title": "Signatureid",
            "description": "Firma que el guest token autoriza (`sgr_…`)."
          },
          "signerId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Signerid",
            "description": "ID del firmante, si aplica."
          },
          "guestToken": {
            "type": "string",
            "title": "Guesttoken",
            "description": "Credencial de un solo uso para el iframe (rotada en cada `init`)."
          },
          "signer": {
            "$ref": "#/components/schemas/SigningSessionSigner",
            "description": "Firmante ligado a la sesión."
          },
          "document": {
            "$ref": "#/components/schemas/SigningSessionDocument",
            "description": "Documento que firma la sesión."
          },
          "brandProfileId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Brandprofileid",
            "description": "Perfil de marca, si se configuró."
          },
          "locale": {
            "type": "string",
            "title": "Locale",
            "description": "Idioma del iframe (ej. `es`)."
          },
          "successUrl": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Successurl",
            "description": "Redirección de éxito."
          },
          "cancelUrl": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Cancelurl",
            "description": "Redirección de cancelación."
          }
        },
        "type": "object",
        "required": [
          "livemode",
          "sessionId",
          "signatureId",
          "guestToken",
          "signer",
          "document",
          "locale"
        ],
        "title": "SigningSessionInit",
        "description": "The fresh signing context the iframe shell exchanges a client secret for.\n\nConsumed only by AllSign's own first-party iframe shell. Inherits\n``livemode``. ``guestToken`` is a one-time credential rotated on every init."
      },
      "SigningSessionInitRequest": {
        "properties": {
          "clientSecret": {
            "type": "string",
            "title": "Clientsecret",
            "description": "El secreto acuñado en el create (forma `as_sess_{id}_secret_{rnd}`). Es la credencial de esta ruta."
          },
          "parentOrigin": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Parentorigin",
            "description": "El origen (`https://…`) de la página que embebe el iframe, para validar contra `allowedOrigins`."
          }
        },
        "type": "object",
        "required": [
          "clientSecret"
        ],
        "title": "SigningSessionInitRequest",
        "description": "Body for the iframe init. Auth = ``clientSecret`` (never Authorization).\n\nThe ``clientSecret`` has the opaque ``as_sess_{id}_secret_{rnd}`` shape; its\n``as_`` prefix collides with the v3 API-key discriminator, so it MUST travel\nin the body only (Red-team R1)."
      },
      "SigningSessionNom151": {
        "properties": {
          "s3Key": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "S3Key",
            "description": "Ruta S3 de la constancia NOM-151."
          },
          "presignedUrl": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Presignedurl",
            "description": "URL prefirmada de la constancia NOM-151."
          },
          "data": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Data",
            "description": "Metadatos de la constancia NOM-151."
          }
        },
        "type": "object",
        "title": "SigningSessionNom151",
        "description": "NOM-151 constancia pointer (present only once the document is sealed)."
      },
      "SigningSessionOtpMode": {
        "type": "string",
        "enum": [
          "none",
          "required",
          "integrator_verified"
        ],
        "title": "SigningSessionOtpMode",
        "description": "Identity-verification mode at create time (opaque snake data tokens).\n\nOnly ``none`` is implemented in the reused v2 service (MVP); ``required`` /\n``integrator_verified`` are frozen placeholders (the service 501s on them).\n\nOpen enum: clients MUST tolerate values not in this list.",
        "x-extensible-enum": true
      },
      "SigningSessionPolicy": {
        "properties": {
          "sessionId": {
            "type": "string",
            "title": "Sessionid",
            "description": "ID de la sesión (`ses_…`)."
          },
          "allowedOrigins": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Allowedorigins",
            "description": "Orígenes autorizados a montar el iframe (los `allowedOrigins` del create)."
          },
          "frameAncestors": {
            "type": "string",
            "title": "Frameancestors",
            "description": "El valor listo para el header `Content-Security-Policy: frame-ancestors`. Es `*` cuando no se configuraron orígenes."
          }
        },
        "type": "object",
        "required": [
          "sessionId",
          "allowedOrigins",
          "frameAncestors"
        ],
        "title": "SigningSessionPolicy",
        "description": "CSP hint for the first-party route serving the iframe HTML.\n\nNOT a resource object (no ``livemode``): operational config, not an\nenvironment-scoped resource — same criterion as ``/healthz``."
      },
      "SigningSessionSignature": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id",
            "description": "ID de la firma (`sgr_…`)."
          },
          "status": {
            "type": "string",
            "title": "Status",
            "description": "Estado autoritativo de la firma."
          },
          "signedAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Signedat",
            "description": "Momento de la firma (ISO 8601)."
          }
        },
        "type": "object",
        "required": [
          "id",
          "status"
        ],
        "title": "SigningSessionSignature",
        "description": "The underlying signature's authoritative state (id is ``sgr_`` prefixed)."
      },
      "SigningSessionSigner": {
        "properties": {
          "email": {
            "type": "string",
            "title": "Email",
            "description": "Correo del participante que firma en el iframe."
          },
          "name": {
            "type": "string",
            "title": "Name",
            "description": "Nombre del firmante."
          }
        },
        "type": "object",
        "required": [
          "email",
          "name"
        ],
        "title": "SigningSessionSigner",
        "description": "The signer bound to a session."
      },
      "SigningSessionStatus": {
        "type": "string",
        "enum": [
          "pending",
          "active",
          "completed",
          "expired",
          "cancelled"
        ],
        "title": "SigningSessionStatus",
        "description": "Public session lifecycle status (opaque snake data tokens, frozen).\n\nMirrors the ``EmbeddedSigningSession.status`` column verbatim — the reused\nv2 service already speaks these lowercase tokens, so no map is needed.\n\nOpen enum: clients MUST tolerate values not in this list.",
        "x-extensible-enum": true
      },
      "TeamActivityList": {
        "properties": {
          "object": {
            "type": "string",
            "const": "list",
            "title": "Object",
            "description": "Siempre `\"list\"`.",
            "default": "list"
          },
          "data": {
            "items": {
              "$ref": "#/components/schemas/TeamMemberActivity"
            },
            "type": "array",
            "title": "Data",
            "description": "Una fila por miembro del equipo."
          },
          "hasMore": {
            "type": "boolean",
            "title": "Hasmore",
            "description": "Siempre `false` — acotada por el número de asientos del tenant.",
            "default": false
          },
          "nextCursor": {
            "type": "null",
            "title": "Nextcursor",
            "description": "Siempre `null` — esta colección no pagina."
          },
          "previousCursor": {
            "type": "null",
            "title": "Previouscursor",
            "description": "Siempre `null` — esta colección no pagina."
          },
          "limit": {
            "type": "null",
            "title": "Limit",
            "description": "Siempre `null` — sin parámetro `limit` en este endpoint."
          }
        },
        "type": "object",
        "required": [
          "data"
        ],
        "title": "TeamActivityList",
        "description": "Bounded, non-paginated collection — one row per tenant member. Same\nenvelope keys as a cursor-paginated list, always ``null`` here (F1.6)."
      },
      "TeamList": {
        "properties": {
          "object": {
            "type": "string",
            "const": "list",
            "title": "Object",
            "description": "Siempre `\"list\"`.",
            "default": "list"
          },
          "data": {
            "items": {
              "$ref": "#/components/schemas/TeamMember"
            },
            "type": "array",
            "title": "Data",
            "description": "Miembros del tenant."
          },
          "hasMore": {
            "type": "boolean",
            "title": "Hasmore",
            "description": "Siempre `false` — colección acotada por los asientos del tenant, sin cursor.",
            "default": false
          },
          "nextCursor": {
            "type": "null",
            "title": "Nextcursor",
            "description": "Siempre `null` — esta colección no pagina."
          },
          "previousCursor": {
            "type": "null",
            "title": "Previouscursor",
            "description": "Siempre `null` — esta colección no pagina."
          },
          "limit": {
            "type": "null",
            "title": "Limit",
            "description": "Siempre `null` — sin parámetro `limit` en este endpoint."
          }
        },
        "type": "object",
        "required": [
          "data"
        ],
        "title": "TeamList",
        "description": "Bounded, non-paginated collection (same convention as\n``TemplateVariableList``) — team size is bounded by tenant seats, never\nlarge enough to need cursor pagination.\n\nCarries the same envelope keys as a cursor-paginated list (always ``null``\nhere) so an SDK can use one generic list-response type across v3 (F1.6)."
      },
      "TeamMember": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id",
            "description": "ID opaco del miembro (`usr_…`)."
          },
          "name": {
            "type": "string",
            "title": "Name",
            "description": "Nombre del miembro."
          },
          "email": {
            "type": "string",
            "title": "Email",
            "description": "Correo del miembro."
          },
          "role": {
            "type": "string",
            "title": "Role",
            "description": "Rol del miembro en el tenant (ej. `owner`, `admin`, `member`)."
          }
        },
        "type": "object",
        "required": [
          "id",
          "name",
          "email",
          "role"
        ],
        "title": "TeamMember",
        "description": "One tenant team member (``GET /v3/users/team``).\n\nNot a :class:`V3ResponseSchema` resource object — no ``livemode``: a team\nmember row is tenant-membership metadata, never itself billed or\nenvironment-scoped on its own (same rationale ``Folder``/``Template``\napply to their own metadata-only rows)."
      },
      "TeamMemberActivity": {
        "properties": {
          "userId": {
            "type": "string",
            "title": "Userid",
            "description": "ID opaco del miembro (`usr_…`) — el mismo prefijo que usa `GET /v3/users/me`, no un UUID crudo."
          },
          "name": {
            "type": "string",
            "title": "Name",
            "description": "Nombre del miembro."
          },
          "initials": {
            "type": "string",
            "title": "Initials",
            "description": "Iniciales para avatar."
          },
          "role": {
            "type": "string",
            "title": "Role",
            "description": "Rol del miembro en el tenant."
          },
          "sent": {
            "type": "integer",
            "title": "Sent",
            "description": "Documentos enviados por el miembro."
          },
          "signed": {
            "type": "integer",
            "title": "Signed",
            "description": "Documentos que el miembro firmó."
          },
          "rate": {
            "type": "number",
            "title": "Rate",
            "description": "Tasa de finalización del miembro."
          }
        },
        "type": "object",
        "required": [
          "userId",
          "name",
          "initials",
          "role",
          "sent",
          "signed",
          "rate"
        ],
        "title": "TeamMemberActivity",
        "description": "Per-member sending/signing stats. ``userId`` is the opaque ``usr_``\nprefixed id (same encoding ``GET /v3/users/me`` uses), not a raw UUID."
      },
      "Template": {
        "properties": {
          "livemode": {
            "type": "boolean",
            "title": "Livemode",
            "description": "`true` en entorno `live`, `false` en `test`/`dev` (marca de agua, sin validez legal)."
          },
          "id": {
            "type": "string",
            "title": "Id",
            "description": "ID de la plantilla (`tmpl_…`)."
          },
          "object": {
            "type": "string",
            "const": "template",
            "title": "Object",
            "description": "Siempre `\"template\"`.",
            "default": "template"
          },
          "name": {
            "type": "string",
            "title": "Name",
            "description": "Nombre de la plantilla."
          },
          "description": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Description",
            "description": "Descripción de la plantilla."
          },
          "fileType": {
            "type": "string",
            "title": "Filetype",
            "description": "Tipo de archivo fuente (ej. `docx`, `pdf`)."
          },
          "variableCount": {
            "type": "integer",
            "title": "Variablecount",
            "description": "Número de variables detectadas en la plantilla."
          },
          "tags": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Tags",
            "description": "Etiquetas de la plantilla (arreglo vacío por default).",
            "default": []
          },
          "category": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Category",
            "description": "Categoría de la plantilla."
          },
          "usageCount": {
            "type": "integer",
            "title": "Usagecount",
            "description": "Cuántas veces se ha usado la plantilla."
          },
          "lastUsedAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Lastusedat",
            "description": "Último uso (ISO 8601)."
          },
          "currentVersion": {
            "type": "integer",
            "title": "Currentversion",
            "description": "Versión actual de la plantilla."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "title": "Createdat",
            "description": "Fecha de creación (ISO 8601)."
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "title": "Updatedat",
            "description": "Última actualización (ISO 8601)."
          }
        },
        "type": "object",
        "required": [
          "livemode",
          "id",
          "name",
          "fileType",
          "variableCount",
          "usageCount",
          "currentVersion",
          "createdAt",
          "updatedAt"
        ],
        "title": "Template",
        "description": "A template resource object. Inherits ``livemode`` from V3ResponseSchema.\n\nReused for both the list items and ``GET /templates/{id}`` (same pattern\nas ``Document``) — variables live on their own sub-resource\n(``GET /templates/{id}/variables``), never embedded here."
      },
      "TemplateList": {
        "properties": {
          "object": {
            "type": "string",
            "const": "list",
            "title": "Object",
            "description": "Siempre `\"list\"`.",
            "default": "list"
          },
          "data": {
            "items": {
              "$ref": "#/components/schemas/Template"
            },
            "type": "array",
            "title": "Data",
            "description": "Arreglo de objetos Template."
          },
          "hasMore": {
            "type": "boolean",
            "title": "Hasmore",
            "description": "`true` si hay más resultados después de esta página."
          },
          "nextCursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Nextcursor",
            "description": "Cursor para la siguiente página (pásalo como `startingAfter`)."
          },
          "previousCursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Previouscursor",
            "description": "Cursor para la página anterior (pásalo como `endingBefore`)."
          },
          "limit": {
            "type": "integer",
            "title": "Limit",
            "description": "El límite aplicado a esta página."
          }
        },
        "type": "object",
        "required": [
          "data",
          "hasMore",
          "limit"
        ],
        "title": "TemplateList",
        "description": "Cursor-paginated envelope. Deliberately NOT a resource object (no\n``livemode``) — the pagination wrapper, same frozen shape as\n``DocumentList``/``EventList``."
      },
      "TemplateSort": {
        "type": "string",
        "enum": [
          "createdAt",
          "-createdAt"
        ],
        "title": "TemplateSort",
        "description": "``?sort=`` whitelist for ``GET /templates``.\n\nSame shape as ``DocumentSort``, and for the same reason: the cursor encodes the\nsort value as an ISO ``datetime``, so only date fields are sortable."
      },
      "TemplateValuesIssue": {
        "properties": {
          "name": {
            "type": "string",
            "title": "Name",
            "description": "La variable a la que se refiere el hallazgo."
          },
          "code": {
            "type": "string",
            "title": "Code",
            "description": "Código estable del hallazgo: `MISSING_REQUIRED_VARIABLE` (falta), `EMPTY_REQUIRED_VARIABLE` (llegó vacía) o `TYPE_MISMATCH_HINT` (el valor no cuadra con el tipo inferido).",
            "examples": [
              "MISSING_REQUIRED_VARIABLE"
            ]
          },
          "detail": {
            "type": "string",
            "title": "Detail",
            "description": "Explicación legible de qué pasaría si envías así el documento."
          }
        },
        "type": "object",
        "required": [
          "name",
          "code",
          "detail"
        ],
        "title": "TemplateValuesIssue"
      },
      "TemplateValuesValidation": {
        "properties": {
          "livemode": {
            "type": "boolean",
            "title": "Livemode",
            "description": "`true` en entorno `live`, `false` en `test`/`dev` (marca de agua, sin validez legal)."
          },
          "object": {
            "type": "string",
            "const": "template_values_validation",
            "title": "Object",
            "description": "Siempre `\"template_values_validation\"`.",
            "default": "template_values_validation"
          },
          "templateId": {
            "type": "string",
            "title": "Templateid",
            "description": "La plantilla contra la que se validó (`tmpl_…`)."
          },
          "valid": {
            "type": "boolean",
            "title": "Valid",
            "description": "`false` únicamente cuando hay `errors`. Los `warnings` no invalidan: el `type` de una variable se infiere de su nombre, así que no puede bloquear."
          },
          "errors": {
            "items": {
              "$ref": "#/components/schemas/TemplateValuesIssue"
            },
            "type": "array",
            "title": "Errors",
            "description": "Problemas que SÍ romperían el documento: una variable requerida ausente o vacía saldría como un espacio en blanco en el contrato. `POST /v3/documents` rechaza con 422 en este caso."
          },
          "warnings": {
            "items": {
              "$ref": "#/components/schemas/TemplateValuesIssue"
            },
            "type": "array",
            "title": "Warnings",
            "description": "Avisos que no bloquean. El `type` de cada variable se **infiere de su nombre** (`monto_…` → `currency`), no está declarado en la plantilla; por eso un desajuste se avisa pero nunca rechaza."
          },
          "ignored": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Ignored",
            "description": "Llaves que mandaste y la plantilla no declara — normalmente un typo. Se descartan al generar el documento, así que conviene revisarlas.",
            "examples": [
              [
                "nombre_completoo"
              ]
            ]
          }
        },
        "type": "object",
        "required": [
          "livemode",
          "templateId",
          "valid"
        ],
        "title": "TemplateValuesValidation",
        "description": "Diagnóstico de un juego de valores. Responde **200 aunque haya problemas**:\nes un ensayo, no un rechazo. No crea documento, no encola nada y no consume\ncrédito — para eso existe."
      },
      "TemplateValuesValidationRequest": {
        "properties": {
          "templateValues": {
            "additionalProperties": {
              "type": "string"
            },
            "type": "object",
            "title": "Templatevalues",
            "description": "El mismo mapa que mandarías en `templateValues` al crear el documento. Las llaves son los `name` de las variables y conservan su forma natural (`nombre_completo`): nunca se camelizan, porque son datos del negocio y no campos del protocolo.",
            "examples": [
              {
                "arrendador__nombre": "María García",
                "monto_renta": "12500.00"
              }
            ]
          }
        },
        "type": "object",
        "title": "TemplateValuesValidationRequest"
      },
      "TemplateVariable": {
        "properties": {
          "name": {
            "type": "string",
            "title": "Name",
            "description": "Nombre de la variable — es la llave que usas en `templateValues`. Se mantiene en `snake_case` natural, nunca se cameliza."
          },
          "label": {
            "type": "string",
            "title": "Label",
            "description": "Etiqueta legible para mostrar."
          },
          "type": {
            "type": "string",
            "title": "Type",
            "description": "Tipo de dato (token opaco `snake_case`): `text`, `date`, `currency`, `textarea`, `select`, `number`.",
            "default": "text"
          },
          "required": {
            "type": "boolean",
            "title": "Required",
            "description": "Si la variable es obligatoria.",
            "default": true
          },
          "defaultValue": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Defaultvalue",
            "description": "Valor por default sugerido."
          },
          "options": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Options",
            "description": "Opciones válidas cuando `type` es `select`."
          },
          "role": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Role",
            "description": "Rol del firmante inferido del prefijo con doble guion bajo, o `null` si la variable no está ligada a un rol."
          }
        },
        "type": "object",
        "required": [
          "name",
          "label"
        ],
        "title": "TemplateVariable",
        "description": "One auto-detected (or curated) Jinja2 variable — enough to build\n``templateValues`` for ``POST /v3/documents``.\n\n``type`` is an opaque ``snake_case`` data token (text/date/currency/\ntextarea/select/number — the v2 ``VariableType`` catalog), never\ncamelized. ``role``, when present, is the double-underscore-inferred\nsigner role prefix (``revelador__nombre`` -> role ``\"Revelador\"``)."
      },
      "TemplateVariableList": {
        "properties": {
          "object": {
            "type": "string",
            "const": "list",
            "title": "Object",
            "description": "Siempre `\"list\"`.",
            "default": "list"
          },
          "templateId": {
            "type": "string",
            "title": "Templateid",
            "description": "La plantilla a la que pertenecen las variables (`tmpl_…`)."
          },
          "data": {
            "items": {
              "$ref": "#/components/schemas/TemplateVariable"
            },
            "type": "array",
            "title": "Data",
            "description": "Arreglo de variables de la plantilla."
          },
          "hasMore": {
            "type": "boolean",
            "title": "Hasmore",
            "description": "Siempre `false` en esta colección acotada.",
            "default": false
          }
        },
        "type": "object",
        "required": [
          "templateId",
          "data"
        ],
        "title": "TemplateVariableList",
        "description": "Bounded, non-paginated collection (same convention as ``SignerList``) —\na template's variable count is bounded by the DOCX itself, never large\nenough to need cursor pagination."
      },
      "TrendList": {
        "properties": {
          "object": {
            "type": "string",
            "const": "list",
            "title": "Object",
            "description": "Siempre `\"list\"`.",
            "default": "list"
          },
          "data": {
            "items": {
              "$ref": "#/components/schemas/MonthlyTrendPoint"
            },
            "type": "array",
            "title": "Data",
            "description": "Un punto por mes (hasta 6)."
          },
          "hasMore": {
            "type": "boolean",
            "title": "Hasmore",
            "description": "Siempre `false`.",
            "default": false
          },
          "nextCursor": {
            "type": "null",
            "title": "Nextcursor",
            "description": "Siempre `null` — esta colección no pagina."
          },
          "previousCursor": {
            "type": "null",
            "title": "Previouscursor",
            "description": "Siempre `null` — esta colección no pagina."
          },
          "limit": {
            "type": "null",
            "title": "Limit",
            "description": "Siempre `null` — sin parámetro `limit` en este endpoint."
          }
        },
        "type": "object",
        "required": [
          "data"
        ],
        "title": "TrendList",
        "description": "Bounded, non-paginated collection — the last 6 months, fixed. Same\nenvelope keys as a cursor-paginated list, always ``null`` here (F1.6)."
      },
      "UserMe": {
        "properties": {
          "livemode": {
            "type": "boolean",
            "title": "Livemode",
            "description": "`true` en entorno `live`, `false` en `test`/`dev` (marca de agua, sin validez legal)."
          },
          "id": {
            "type": "string",
            "title": "Id",
            "description": "ID opaco del usuario detrás de la credencial (`usr_…`)."
          },
          "email": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Email",
            "description": "Correo del usuario, si está disponible."
          },
          "tenantId": {
            "type": "string",
            "title": "Tenantid",
            "description": "ID opaco del tenant (`ten_…`)."
          },
          "scopes": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Scopes",
            "description": "Los scopes que trae tu API key (ej. `[\"document:read\", \"document:write\"]`)."
          },
          "environment": {
            "type": "string",
            "title": "Environment",
            "description": "Entorno de la key: `live` o `test`."
          },
          "authMode": {
            "type": "string",
            "title": "Authmode",
            "description": "Modo de autenticación con el que se resolvió la petición (ej. `api_key`)."
          }
        },
        "type": "object",
        "required": [
          "livemode",
          "id",
          "tenantId",
          "scopes",
          "environment",
          "authMode"
        ],
        "title": "UserMe",
        "description": "The principal behind the credential. camelCase out (``tenantId``);\n``livemode`` from :class:`V3ResponseSchema`."
      },
      "ValidationError": {
        "properties": {
          "loc": {
            "items": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "integer"
                }
              ]
            },
            "type": "array",
            "title": "Location"
          },
          "msg": {
            "type": "string",
            "title": "Message"
          },
          "type": {
            "type": "string",
            "title": "Error Type"
          }
        },
        "type": "object",
        "required": [
          "loc",
          "msg",
          "type"
        ],
        "title": "ValidationError"
      },
      "VerifyRequest": {
        "properties": {
          "hashSha256": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 64,
                "minLength": 64
              },
              {
                "type": "null"
              }
            ],
            "title": "Hashsha256"
          },
          "constancia": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Constancia"
          },
          "constanciaId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Constanciaid"
          }
        },
        "type": "object",
        "title": "VerifyRequest"
      },
      "VerifyResponse": {
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "VALID",
              "INDETERMINATE",
              "INVALID"
            ],
            "title": "Status"
          },
          "reason": {
            "type": "string",
            "title": "Reason"
          },
          "hashSha256": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Hashsha256"
          }
        },
        "type": "object",
        "required": [
          "status",
          "reason"
        ],
        "title": "VerifyResponse"
      },
      "VoidRequest": {
        "properties": {
          "reason": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Reason",
            "description": "Motivo de la anulación (queda en la bitácora del documento)."
          }
        },
        "type": "object",
        "title": "VoidRequest"
      },
      "WebhookDeliveryAttempt": {
        "properties": {
          "attemptNumber": {
            "type": "integer",
            "title": "Attemptnumber",
            "description": "Número de intento (1, 2, 3, …)."
          },
          "outcome": {
            "type": "string",
            "title": "Outcome",
            "description": "Resultado del intento: `SENT`, `TRANSIENT` o `PERMANENT`."
          },
          "statusCode": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Statuscode",
            "description": "Código HTTP que respondió el endpoint del cliente."
          },
          "responseBody": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Responsebody",
            "description": "Cuerpo de la respuesta del endpoint (truncado)."
          },
          "error": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Error",
            "description": "Error de red o de timeout, si lo hubo."
          },
          "durationMs": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Durationms",
            "description": "Duración del intento en milisegundos."
          },
          "attemptedAt": {
            "type": "string",
            "format": "date-time",
            "title": "Attemptedat",
            "description": "Cuándo se hizo este intento (ISO 8601)."
          }
        },
        "type": "object",
        "required": [
          "attemptNumber",
          "outcome",
          "attemptedAt"
        ],
        "title": "WebhookDeliveryAttempt"
      },
      "WebhookDeliveryList": {
        "properties": {
          "object": {
            "type": "string",
            "const": "list",
            "title": "Object",
            "description": "Siempre `\"list\"`.",
            "default": "list"
          },
          "data": {
            "items": {
              "$ref": "#/components/schemas/WebhookDeliveryResponse"
            },
            "type": "array",
            "title": "Data",
            "description": "Arreglo de entregas del webhook."
          },
          "hasMore": {
            "type": "boolean",
            "title": "Hasmore",
            "description": "`true` si hay más resultados después de esta página."
          },
          "nextCursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Nextcursor",
            "description": "Cursor para la siguiente página (pásalo como `startingAfter`)."
          },
          "previousCursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Previouscursor",
            "description": "Cursor para la página anterior (pásalo como `endingBefore`)."
          },
          "limit": {
            "type": "integer",
            "title": "Limit",
            "description": "El límite aplicado a esta página."
          }
        },
        "type": "object",
        "required": [
          "data",
          "hasMore",
          "limit"
        ],
        "title": "WebhookDeliveryList"
      },
      "WebhookDeliveryResponse": {
        "properties": {
          "livemode": {
            "type": "boolean",
            "title": "Livemode",
            "description": "`true` en entorno `live`, `false` en `test`/`dev` (marca de agua, sin validez legal)."
          },
          "id": {
            "type": "string",
            "title": "Id",
            "description": "ID de la entrega (`whd_…`)."
          },
          "object": {
            "type": "string",
            "const": "webhook_delivery",
            "title": "Object",
            "description": "Siempre `\"webhook_delivery\"`.",
            "default": "webhook_delivery"
          },
          "eventId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Eventid",
            "description": "Evento que originó esta entrega (`evt_…`)."
          },
          "eventType": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Eventtype",
            "description": "Tipo de evento entregado."
          },
          "status": {
            "type": "string",
            "title": "Status",
            "description": "Estado de la entrega: `PENDING`, `SENT` o `FAILED`."
          },
          "targetUrl": {
            "type": "string",
            "title": "Targeturl",
            "description": "URL del endpoint al que se intentó entregar."
          },
          "attempts": {
            "type": "integer",
            "title": "Attempts",
            "description": "Número total de intentos realizados."
          },
          "lastStatusCode": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Laststatuscode",
            "description": "Código HTTP del último intento."
          },
          "lastError": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Lasterror",
            "description": "Error del último intento, si lo hubo."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "title": "Createdat",
            "description": "Fecha de creación de la entrega (ISO 8601)."
          },
          "sentAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Sentat",
            "description": "Cuándo se entregó exitosamente."
          },
          "attemptHistory": {
            "items": {
              "$ref": "#/components/schemas/WebhookDeliveryAttempt"
            },
            "type": "array",
            "title": "Attempthistory",
            "description": "Historial de intentos de esta entrega.",
            "default": []
          }
        },
        "type": "object",
        "required": [
          "livemode",
          "id",
          "status",
          "targetUrl",
          "attempts",
          "createdAt"
        ],
        "title": "WebhookDeliveryResponse"
      },
      "WebhookEndpointCreate": {
        "properties": {
          "url": {
            "type": "string",
            "title": "Url",
            "description": "URL absoluta `https://` que recibirá los eventos."
          },
          "events": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Events",
            "description": "Tipos de evento a los que te suscribes (catálogo v3)."
          },
          "description": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Description",
            "description": "Descripción legible del endpoint."
          }
        },
        "type": "object",
        "required": [
          "url",
          "events"
        ],
        "title": "WebhookEndpointCreate",
        "description": "Create a webhook endpoint. ``environment`` is taken from the API key, not\nthe body, so a live/test cross is impossible."
      },
      "WebhookEndpointCreatedResponse": {
        "properties": {
          "livemode": {
            "type": "boolean",
            "title": "Livemode",
            "description": "`true` en entorno `live`, `false` en `test`/`dev` (marca de agua, sin validez legal)."
          },
          "id": {
            "type": "string",
            "title": "Id",
            "description": "ID del webhook endpoint (`whe_…`)."
          },
          "object": {
            "type": "string",
            "const": "webhook_endpoint",
            "title": "Object",
            "description": "Siempre `\"webhook_endpoint\"`.",
            "default": "webhook_endpoint"
          },
          "url": {
            "type": "string",
            "title": "Url",
            "description": "URL `https://` que recibe los eventos."
          },
          "events": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Events",
            "description": "Eventos a los que está suscrito este endpoint."
          },
          "description": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Description",
            "description": "Descripción legible del endpoint."
          },
          "status": {
            "type": "string",
            "title": "Status",
            "description": "Estado del endpoint: `enabled` o `disabled`."
          },
          "apiVersion": {
            "type": "string",
            "title": "Apiversion",
            "description": "Versión del contrato de eventos que firma este endpoint."
          },
          "environment": {
            "type": "string",
            "title": "Environment",
            "description": "Entorno del endpoint: `live`, `test` o `dev`."
          },
          "secretLast4": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Secretlast4",
            "description": "Últimos 4 caracteres del secreto vigente (nunca el secreto completo)."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "title": "Createdat",
            "description": "Fecha de creación (ISO 8601)."
          },
          "secret": {
            "type": "string",
            "title": "Secret",
            "description": "Secreto `whsec_…` en claro. Se devuelve solo esta vez — guárdalo al recibirlo."
          }
        },
        "type": "object",
        "required": [
          "livemode",
          "id",
          "url",
          "events",
          "status",
          "apiVersion",
          "environment",
          "createdAt",
          "secret"
        ],
        "title": "WebhookEndpointCreatedResponse",
        "description": "Create / rotate response — carries the cleartext ``secret`` ONCE."
      },
      "WebhookEndpointList": {
        "properties": {
          "object": {
            "type": "string",
            "const": "list",
            "title": "Object",
            "description": "Siempre `\"list\"`.",
            "default": "list"
          },
          "data": {
            "items": {
              "$ref": "#/components/schemas/WebhookEndpointResponse"
            },
            "type": "array",
            "title": "Data",
            "description": "Arreglo de webhook endpoints."
          },
          "hasMore": {
            "type": "boolean",
            "title": "Hasmore",
            "description": "`true` si hay más resultados después de esta página."
          },
          "nextCursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Nextcursor",
            "description": "Cursor para la siguiente página (pásalo como `startingAfter`)."
          },
          "previousCursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Previouscursor",
            "description": "Cursor para la página anterior (pásalo como `endingBefore`)."
          },
          "limit": {
            "type": "integer",
            "title": "Limit",
            "description": "El límite aplicado a esta página."
          }
        },
        "type": "object",
        "required": [
          "data",
          "hasMore",
          "limit"
        ],
        "title": "WebhookEndpointList"
      },
      "WebhookEndpointResponse": {
        "properties": {
          "livemode": {
            "type": "boolean",
            "title": "Livemode",
            "description": "`true` en entorno `live`, `false` en `test`/`dev` (marca de agua, sin validez legal)."
          },
          "id": {
            "type": "string",
            "title": "Id",
            "description": "ID del webhook endpoint (`whe_…`)."
          },
          "object": {
            "type": "string",
            "const": "webhook_endpoint",
            "title": "Object",
            "description": "Siempre `\"webhook_endpoint\"`.",
            "default": "webhook_endpoint"
          },
          "url": {
            "type": "string",
            "title": "Url",
            "description": "URL `https://` que recibe los eventos."
          },
          "events": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Events",
            "description": "Eventos a los que está suscrito este endpoint."
          },
          "description": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Description",
            "description": "Descripción legible del endpoint."
          },
          "status": {
            "type": "string",
            "title": "Status",
            "description": "Estado del endpoint: `enabled` o `disabled`."
          },
          "apiVersion": {
            "type": "string",
            "title": "Apiversion",
            "description": "Versión del contrato de eventos que firma este endpoint."
          },
          "environment": {
            "type": "string",
            "title": "Environment",
            "description": "Entorno del endpoint: `live`, `test` o `dev`."
          },
          "secretLast4": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Secretlast4",
            "description": "Últimos 4 caracteres del secreto vigente (nunca el secreto completo)."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "title": "Createdat",
            "description": "Fecha de creación (ISO 8601)."
          }
        },
        "type": "object",
        "required": [
          "livemode",
          "id",
          "url",
          "events",
          "status",
          "apiVersion",
          "environment",
          "createdAt"
        ],
        "title": "WebhookEndpointResponse",
        "description": "A webhook endpoint (no secret — only ``secretLast4``). Inherits ``livemode``."
      },
      "WebhookEndpointUpdate": {
        "properties": {
          "url": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Url",
            "description": "Nueva URL `https://` del endpoint."
          },
          "events": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Events",
            "description": "Nuevo conjunto de eventos suscritos (reemplaza al anterior)."
          },
          "description": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Description",
            "description": "Nueva descripción del endpoint."
          },
          "disabled": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Disabled",
            "description": "`true` para deshabilitar el endpoint sin borrarlo."
          }
        },
        "additionalProperties": false,
        "type": "object",
        "title": "WebhookEndpointUpdate",
        "description": "Merge-patch: only the fields present are changed. ``extra='forbid'`` → a\n422 on any immutable/unknown field."
      },
      "WebhookEventCatalog": {
        "properties": {
          "object": {
            "type": "string",
            "const": "list",
            "title": "Object",
            "description": "Siempre `\"list\"`.",
            "default": "list"
          },
          "data": {
            "items": {
              "$ref": "#/components/schemas/WebhookEventCatalogEntry"
            },
            "type": "array",
            "title": "Data",
            "description": "Catálogo de eventos v3 suscribibles."
          }
        },
        "type": "object",
        "required": [
          "data"
        ],
        "title": "WebhookEventCatalog"
      },
      "WebhookEventCatalogEntry": {
        "properties": {
          "event": {
            "type": "string",
            "title": "Event",
            "description": "Nombre del evento (ej. `document.completed`)."
          },
          "description": {
            "type": "string",
            "title": "Description",
            "description": "Descripción legible del evento."
          },
          "category": {
            "type": "string",
            "title": "Category",
            "description": "Categoría del evento (ej. `document`, `signer`)."
          },
          "apiVersion": {
            "type": "string",
            "title": "Apiversion",
            "description": "Versión del contrato de eventos que define este evento."
          },
          "status": {
            "type": "string",
            "title": "Status",
            "description": "`active` si ya se emite, `reserved` si está congelado a futuro."
          }
        },
        "type": "object",
        "required": [
          "event",
          "description",
          "category",
          "apiVersion",
          "status"
        ],
        "title": "WebhookEventCatalogEntry"
      },
      "Problem": {
        "description": "An RFC 9457 problem document (flat). Core members lowercase; extensions\ncamelCase via the v3 alias generator (``request_id`` -> ``requestId``).",
        "properties": {
          "type": {
            "default": "about:blank",
            "description": "URI that identifies the error type; resolves to a docs page.",
            "title": "Type",
            "type": "string"
          },
          "title": {
            "description": "Short, human-readable summary of the problem (stable per `code`).",
            "title": "Title",
            "type": "string"
          },
          "status": {
            "description": "The HTTP status code, repeated here for RFC 9457 completeness.",
            "title": "Status",
            "type": "integer"
          },
          "detail": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Human-readable explanation specific to this occurrence.",
            "title": "Detail"
          },
          "instance": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "The request path that produced this error.",
            "title": "Instance"
          },
          "code": {
            "description": "Stable, machine-readable `UPPER_SNAKE` error code (never renamed once shipped).",
            "title": "Code",
            "type": "string"
          },
          "requestId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Correlation id — matches the `AllSign-Request-Id` response header.",
            "title": "Requestid"
          },
          "docsUrl": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Optional deep link to this error's documentation.",
            "title": "Docsurl"
          },
          "errors": {
            "anyOf": [
              {
                "items": {
                  "$ref": "#/components/schemas/ProblemError"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Per-field failures for a 422 validation error.",
            "title": "Errors"
          }
        },
        "required": [
          "title",
          "status",
          "code"
        ],
        "title": "Problem",
        "type": "object"
      },
      "ProblemError": {
        "description": "One field-level failure inside a 422 ``errors[]`` array.",
        "properties": {
          "field": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "camelCase dot/bracket path to the offending field, e.g. `signers[0].email`.",
            "title": "Field"
          },
          "pointer": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "RFC 6901 JSON Pointer to the offending field, e.g. `/signers/0/email`.",
            "title": "Pointer"
          },
          "code": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Stable `UPPER_SNAKE` token for this field failure (`REQUIRED`, `INVALID_TYPE`, …).",
            "title": "Code"
          },
          "detail": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Human-readable message for this field failure.",
            "title": "Detail"
          }
        },
        "title": "ProblemError",
        "type": "object"
      }
    },
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "API key: Authorization: Bearer allsign_live_sk_…"
      },
      "oauth2": {
        "type": "oauth2",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://auth.allsign.io/oauth2/auth",
            "tokenUrl": "https://auth.allsign.io/oauth2/token",
            "scopes": {
              "document:read": "Read documents",
              "document:write": "Create, send and void documents",
              "signature:read": "Read signatures",
              "analytics:read": "Read analytics",
              "constancia:read": "Read standalone NOM-151 constancias",
              "constancia:write": "Issue standalone NOM-151 constancias"
            }
          }
        },
        "description": "OAuth 2.1 (Authorization Code + PKCE) — NOT enabled yet (fast-follow, Ory Hydra)."
      }
    }
  },
  "tags": [
    {
      "name": "Documents",
      "description": "Create, send, void and list documents for signature — from a template or an inline base64 file. One endpoint, two sources."
    },
    {
      "name": "Templates",
      "description": "Read-only: discover your reusable templates and the variables each one needs to build `templateValues` for `POST /v3/documents`."
    },
    {
      "name": "Folders",
      "description": "Organize documents into a folder hierarchy: create, read, rename, move, delete, and list a folder's documents."
    },
    {
      "name": "Analytics",
      "description": "Read-only tenant signing metrics: KPIs, funnel, monthly trend, bottlenecks, team activity and recent events. All require `analytics:read`."
    },
    {
      "name": "Users",
      "description": "Identify the principal behind your API key (`/users/me`, never 403) and list your tenant's team members (`/users/team`, requires `user:read`)."
    },
    {
      "name": "Webhooks",
      "description": "Manage webhook endpoints (create, rotate secret, list deliveries) for the v3 event catalog — HMAC-signed, tenant-scoped."
    },
    {
      "name": "Embedded Signing",
      "description": "Signing sessions for the embedded (iframe) surface: mint a `clientSecret` server-side, then the iframe shell exchanges it for a guest token and reads the CSP policy through the two public first-party routes."
    },
    {
      "name": "Constancias",
      "description": "Issue and retrieve standalone NOM-151 constancias from a SHA-256 hash without uploading the document."
    }
  ],
  "x-webhookEvents": [
    {
      "event": "document.created",
      "description": "A document was created via the API.",
      "category": "Documents",
      "apiVersion": "2026-07-11",
      "status": "active"
    },
    {
      "event": "document.sent",
      "description": "A document left creation and entered the signing cycle (first invitations dispatched).",
      "category": "Documents",
      "apiVersion": "2026-07-11",
      "status": "active"
    },
    {
      "event": "document.completed",
      "description": "All parties signed and the evidence PDF is ready (delivered by stable API URL, not inline).",
      "category": "Documents",
      "apiVersion": "2026-07-11",
      "status": "active"
    },
    {
      "event": "document.voided",
      "description": "A document was voided (annulled). NOM-151 retention keeps the record.",
      "category": "Documents",
      "apiVersion": "2026-07-11",
      "status": "active"
    },
    {
      "event": "document.expired",
      "description": "A document reached its expiry date without being completed. Carries who did manage to sign.",
      "category": "Documents",
      "apiVersion": "2026-07-11",
      "status": "active"
    },
    {
      "event": "document.fill_started",
      "description": "The document entered data-fill: role-bound variables are pending.",
      "category": "Documents",
      "apiVersion": "2026-07-11",
      "status": "active"
    },
    {
      "event": "document.ready_to_sign",
      "description": "The PDF was materialized with the filled data and is ready to sign.",
      "category": "Documents",
      "apiVersion": "2026-07-11",
      "status": "active"
    },
    {
      "event": "signer.signed",
      "description": "One signer completed their signature. Carries the running progress.",
      "category": "Signers",
      "apiVersion": "2026-07-11",
      "status": "active"
    },
    {
      "event": "signer.fill_completed",
      "description": "A signer finished filling the variables assigned to their role.",
      "category": "Signers",
      "apiVersion": "2026-07-11",
      "status": "active"
    },
    {
      "event": "signer.reminder_sent",
      "description": "A signing reminder was sent to a signer (email or WhatsApp).",
      "category": "Signers",
      "apiVersion": "2026-07-11",
      "status": "active"
    },
    {
      "event": "signer.declined",
      "description": "A signer declined to sign. RESERVED — the contract is frozen; it does not fire yet.",
      "category": "Signers",
      "apiVersion": "2026-07-11",
      "status": "reserved"
    },
    {
      "event": "nom151.constancia.issued",
      "description": "The NOM-151 conservation constancia was issued for a completed document.",
      "category": "Compliance",
      "apiVersion": "2026-07-11",
      "status": "active"
    }
  ],
  "security": [
    {
      "apiKey": []
    },
    {
      "oauth2": []
    }
  ],
  "x-domainIntros": {
    "documents": {
      "title": "Documents",
      "metaDescription": "Crea, envía y gestiona documentos de firma con la API v3 de AllSign. Un solo endpoint firma una plantilla o un PDF subido en base64.",
      "lead": "Un documento representa un archivo listo para firma electrónica con biometría, anti-deepfake y NOM-151. En la API v3 un **solo endpoint** (`POST /v3/documents`) crea el documento a partir de una **plantilla** o de un **PDF subido en base64** — tú eliges la fuente con el campo `source`.",
      "notes": [
        "Todas las respuestas usan **camelCase** en el wire, ids opacos con prefijo (`doc_`, `tmpl_`, `fld_`, `sgr_`, `evt_`) y `livemode` para distinguir entorno `live` de `test`. Los errores siguen **problem+json** (RFC 9457) con un campo `code` en `UPPER_SNAKE`. Las listas paginan por cursor (`startingAfter` / `endingBefore` + `hasMore`) y las respuestas traen headers `RateLimit-*`."
      ]
    },
    "templates": {
      "title": "Templates",
      "metaDescription": "Consulta plantillas y sus variables con la API v3 de AllSign para armar templateValues al crear documentos.",
      "lead": "Una plantilla es un documento reutilizable (con variables) que ya subiste a AllSign. Ningún endpoint de esta página modifica nada: sirven para descubrir qué plantillas tienes, qué variables llenar y **si tus valores están completos antes de gastar un crédito**. La creación de un documento a partir de una plantilla **no vive aquí** — se hace con `POST /v3/documents` usando `source: \"template\"`.",
      "notes": [
        "Para firmar con una plantilla, usa [Create document](/endpoints/documents#create-document) con `source: \"template\"`, el `templateId` y el mapa `templateValues`. Esta página te ayuda a **encontrar** la plantilla, **conocer sus variables** y **ensayar los valores**.",
        "El orden que recomendamos al integrar: **Get variables** para saber qué se pide, **Validate values** para confirmar que tu mapa está completo, y recién entonces `POST /v3/documents`. Validar no cuesta crédito y no crea nada, así que puedes llamarlo en cada guardado de tu formulario."
      ]
    },
    "folders": {
      "title": "Folders",
      "metaDescription": "Organiza documentos en carpetas con la API v3 de AllSign: crear, consultar, actualizar, eliminar y listar documentos por carpeta.",
      "lead": "Las carpetas te dejan organizar documentos en una jerarquía. Puedes crearlas, consultarlas, renombrarlas, moverlas, eliminarlas y listar los documentos que contienen.",
      "notes": [
        "Los ids de carpeta llevan el prefijo `fld_`. Una carpeta puede anidarse bajo otra vía `parentId`; `null` (u omitido) significa nivel raíz."
      ]
    },
    "analytics": {
      "title": "Analytics",
      "metaDescription": "Métricas de firma de tu tenant con la API v3 de AllSign: KPIs, embudo, tendencia, cuellos de botella, actividad por miembro y eventos recientes. Todos exigen el scope analytics:read.",
      "lead": "Los endpoints de Analytics resumen la actividad de firma de tu tenant: indicadores clave, el embudo de firma, la tendencia mensual, quién frena los documentos, la actividad por miembro del equipo y los eventos más recientes. Son de **solo lectura** y agregan datos que ya viven en tus documentos.",
      "notes": [
        "**Los seis endpoints exigen el scope `analytics:read`** (o `analytics:*`). Una API key con solo `document:*` recibe **403 `PERMISSION_DENIED`** con la extensión `requiredScope: \"analytics:read\"` — genera o edita una key con ese scope en el Dashboard antes de consultarlos.",
        "Todas las respuestas usan **camelCase** en el wire e ids opacos con prefijo (`usr_`, `evt_`). Los errores siguen **problem+json** (RFC 9457) con un `code` en `UPPER_SNAKE`. Estas listas son **colecciones acotadas** (`object: \"list\"` con `hasMore` siempre `false`): NO paginan por cursor — su tamaño lo limita el propio endpoint (el embudo tiene 4 etapas, la tendencia 6 meses, etc.). Cada respuesta trae headers `RateLimit-*`."
      ]
    },
    "users": {
      "title": "Users",
      "metaDescription": "Identifica al principal detrás de tu API key y lista los miembros de tu tenant con la API v3 de AllSign. GET /v3/users/me responde 200 o 401, nunca 403.",
      "lead": "Dos endpoints para conocer **quién eres** frente a la API y **quién más** está en tu tenant. `GET /v3/users/me` identifica al principal detrás de la credencial (útil para verificar scopes y entorno); `GET /v3/users/team` lista a los miembros del equipo.",
      "notes": [
        "Las respuestas usan **camelCase** en el wire e ids opacos con prefijo (`usr_`, `ten_`). Los errores siguen **problem+json** (RFC 9457) con un `code` en `UPPER_SNAKE`. `GET /v3/users/team` es una **colección acotada** (`object: \"list\"`, `hasMore` siempre `false`): su tamaño lo limitan los asientos del tenant, nunca necesita cursor. Cada respuesta trae headers `RateLimit-*`."
      ]
    },
    "signing-sessions": {
      "title": "Signing sessions",
      "metaDescription": "Firma embebida (iframe) con la API v3 de AllSign: crea una sesión, obtén su estado con la evidencia expandible, intercambia el client secret por un guest token y consulta la política CSP del iframe.",
      "lead": "Las **signing sessions** son la superficie de firma embebida (iframe) de la API v3: acuñas un `clientSecret` que autoriza al SDK del iframe a firmar como un participante concreto de un documento existente, y tu app monta el iframe sin sacar al firmante de tu producto.",
      "notes": [
        "**Superficie nueva en v3.** El embedded de la v2 sigue vivo bajo [`/v2/embedded`](/v2/embedded) y no se toca; esta es una superficie que **coexiste** con él, con auth, ids y contrato v3. Migra cuando quieras — no hay corte.",
        "Hay **dos modelos de autenticación** en esta página: (1) **Rutas con API key** (`POST /v3/signing-sessions`, `GET /v3/signing-sessions/{id}`) — tu servidor las llama con `Authorization: Bearer allsign_..._sk_...` y scope `embedded:write`. (2) **Rutas públicas de primera parte** (`…/init`, `…/policy`) — **no** llevan `Authorization`. `init` se autentica con el `clientSecret` **en el body**; `policy` es una consulta pública por id. Las consume el shell del iframe de AllSign, no tu backend.",
        "Ids opacos con prefijo (`ses_` sesión, `doc_` documento, `sgr_` firma), **camelCase** en el wire, `livemode` para distinguir entorno, y errores **problem+json** (RFC 9457) con `code` en `UPPER_SNAKE`."
      ]
    },
    "webhooks": {
      "title": "Webhooks",
      "metaDescription": "Registra endpoints firmados, gestiona secretos y consulta entregas con la API v3 de AllSign. Para el catálogo de eventos y la verificación de AllSign-Signature, ve la guía de Webhooks.",
      "lead": "Referencia de los 8 endpoints para gestionar tus **webhook endpoints**: registrar, listar, consultar, actualizar, eliminar, rotar secreto, revisar entregas y consultar el catálogo de eventos.",
      "notes": [
        "Esta página es la **referencia de endpoints**. Para cómo funcionan los webhooks de punta a punta (el sobre del evento, verificar `AllSign-Signature`, el catálogo completo de payloads y buenas prácticas), ve la [guía de Webhooks](/webhooks).",
        "Ids opacos con prefijo (`whe_` endpoint, `whd_` entrega, `evt_` evento), **camelCase** en el wire, errores **problem+json** (RFC 9457) con `code` en `UPPER_SNAKE`, y las listas de endpoints y entregas **paginan por cursor** (`startingAfter` / `endingBefore` + `hasMore`). Cada respuesta trae headers `RateLimit-*`."
      ]
    }
  }
}