{
  "openapi": "3.0.3",
  "info": {
    "title": "SAT Captcha Solver",
    "version": "1.0.0",
    "description": "OCR del captcha de login SAT mediante ONNX local. El cliente conserva la sesión SAT y envía el código al formulario. POST conserva la clave y el contrato del IDP. Cada POST se registra en el IDP y conserva su tarifa comercial; total_cost es coste de modelo cero, no precio al cliente. GET de documentación es público y no genera ejecuciones de reconocimiento."
  },
  "servers": [
    {
      "url": "https://sat.ai.prevalentware.com",
      "description": "Producción"
    }
  ],
  "externalDocs": {
    "description": "Guía Markdown para agentes y ejemplos Python",
    "url": "https://sat.ai.prevalentware.com/docs"
  },
  "paths": {
    "/": {
      "get": {
        "operationId": "readSwagger",
        "summary": "Swagger UI y enlaces a la documentación",
        "security": [],
        "responses": {
          "200": {
            "description": "Documentación HTML pública",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "solveSatCaptcha",
        "summary": "Reconocer el captcha SAT",
        "description": "JSON máximo 3 MiB. Cada imagen admite hasta 1 MiB decodificado y 4 000 000 píxeles. Formatos PNG, JPEG, GIF y WebP. Se procesa la primera imagen; la segunda se valida y cuenta como otra página, conservando el payload color/gris del IDP. No admite PDF, file ni s3_key. No hay idempotencia de cliente: repetir un POST puede generar otro cobro.",
        "security": [
          {
            "ApiKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CaptchaRequest"
              },
              "examples": {
                "oneImage": {
                  "summary": "Una imagen, respuesta estructurada",
                  "value": {
                    "prompt": "Reconocer el captcha",
                    "images": [
                      "data:image/png;base64,<BASE64_DE_CAPTCHA_PNG>"
                    ],
                    "response_type": "json"
                  }
                },
                "legacyRpa": {
                  "summary": "Payload existente del RPA (sustituir los marcadores por imágenes)",
                  "value": {
                    "prompt": "Reconocer el captcha",
                    "images": [
                      "data:image/png;base64,<BASE64_COLOR>",
                      "data:image/png;base64,<BASE64_GRIS>"
                    ],
                    "response_type": "json",
                    "provider": "anthropic",
                    "model": "sonnet-4.6"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Resultado y metadatos; publicación contable confirmada, escritura BD asíncrona",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CaptchaResponse"
                }
              }
            }
          },
          "400": {
            "description": "Entrada inválida; corregir antes de repetir",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HandlerError"
                }
              }
            }
          },
          "403": {
            "description": "Clave ausente, inválida o no autorizada",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/GatewayError"
                    },
                    {
                      "$ref": "#/components/schemas/HandlerError"
                    }
                  ]
                }
              }
            }
          },
          "429": {
            "description": "Límite o cuota de API Gateway; esperar con backoff y jitter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                }
              }
            }
          },
          "500": {
            "description": "Error de inferencia o integración",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/HandlerError"
                    },
                    {
                      "$ref": "#/components/schemas/GatewayError"
                    }
                  ]
                }
              }
            }
          },
          "503": {
            "description": "Publicación contable temporalmente no disponible",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HandlerError"
                }
              }
            }
          },
          "504": {
            "description": "Timeout de integración; ejecución y cobro pueden ser inciertos",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                }
              }
            }
          }
        }
      }
    },
    "/openapi.json": {
      "get": {
        "operationId": "readOpenApi",
        "summary": "Contrato OpenAPI 3.0 JSON",
        "security": [],
        "responses": {
          "200": {
            "description": "Especificación pública",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/docs": {
      "get": {
        "operationId": "readAgentGuide",
        "summary": "Guía de integración en Markdown",
        "security": [],
        "responses": {
          "200": {
            "description": "Texto Markdown legible sin JavaScript",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key",
        "description": "Clave existente autorizada del IDP. No publicarla ni incluirla en prompts."
      }
    },
    "schemas": {
      "CaptchaRequest": {
        "type": "object",
        "required": [
          "prompt",
          "images"
        ],
        "properties": {
          "prompt": {
            "type": "string",
            "description": "Hasta 32 000 bytes UTF-8; aceptado por compatibilidad, no dirige la inferencia."
          },
          "images": {
            "type": "array",
            "minItems": 1,
            "maxItems": 2,
            "items": {
              "type": "string",
              "minLength": 1,
              "description": "Base64 puro o data URI image/*; el tipo declarado debe coincidir con los bytes."
            }
          },
          "response_type": {
            "type": "string",
            "enum": [
              "json",
              "text"
            ],
            "default": "text",
            "description": "Con json result es objeto; con text es un string JSON."
          },
          "provider": {
            "type": "string",
            "description": "Campo heredado opcional; la respuesta identifica siempre ONNX.",
            "example": "anthropic"
          },
          "model": {
            "type": "string",
            "description": "Campo heredado opcional; no selecciona otros modelos.",
            "example": "sonnet-4.6"
          },
          "zdr": {
            "type": "boolean",
            "default": false,
            "description": "Omitir contenido en el registro contable; conservar medición y tarifa."
          }
        }
      },
      "CaptchaResult": {
        "type": "object",
        "required": [
          "codigo",
          "confianza"
        ],
        "properties": {
          "codigo": {
            "type": "string",
            "pattern": "^[Y65WRD98SMBG3NJ21CP4KF7ZXHVTQL]{6}$",
            "example": "SCH57K"
          },
          "confianza": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Score CTC no calibrado. No es probabilidad de aceptación SAT.",
            "example": 0.999814
          }
        }
      },
      "CaptchaResponse": {
        "type": "object",
        "required": [
          "status",
          "data"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "success"
            ]
          },
          "data": {
            "type": "object",
            "required": [
              "result",
              "format",
              "timestamp",
              "input_tokens",
              "output_tokens",
              "cache_read_input_tokens",
              "cache_write_input_tokens",
              "s3_path",
              "page_count",
              "provider",
              "model",
              "model_id",
              "total_cost",
              "provider_request_id"
            ],
            "properties": {
              "result": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/CaptchaResult"
                  },
                  {
                    "type": "string",
                    "description": "JSON serializado de CaptchaResult cuando format es text.",
                    "example": "{\"codigo\":\"SCH57K\",\"confianza\":0.999814}"
                  }
                ]
              },
              "format": {
                "type": "string",
                "enum": [
                  "json",
                  "text"
                ]
              },
              "timestamp": {
                "type": "string",
                "description": "Fecha ISO 8601 del servidor; puede no incluir zona horaria.",
                "example": "2026-10-14T10:50:56.126732"
              },
              "input_tokens": {
                "type": "integer",
                "enum": [
                  0
                ]
              },
              "output_tokens": {
                "type": "integer",
                "enum": [
                  0
                ]
              },
              "cache_read_input_tokens": {
                "type": "integer",
                "enum": [
                  0
                ]
              },
              "cache_write_input_tokens": {
                "type": "integer",
                "enum": [
                  0
                ]
              },
              "s3_path": {
                "type": "string",
                "nullable": true,
                "enum": [
                  null
                ]
              },
              "page_count": {
                "type": "integer",
                "minimum": 1,
                "maximum": 2
              },
              "provider": {
                "type": "string",
                "enum": [
                  "onnx"
                ]
              },
              "model": {
                "type": "string",
                "enum": [
                  "sat-captcha-boxfactura"
                ]
              },
              "model_id": {
                "type": "string",
                "pattern": "^boxfactura:[a-f0-9]{64}$",
                "description": "Identificador del checksum del modelo utilizado."
              },
              "total_cost": {
                "type": "number",
                "enum": [
                  0
                ],
                "description": "Coste del modelo; no representa precio comercial ni coste de AWS."
              },
              "provider_request_id": {
                "type": "string",
                "format": "uuid",
                "description": "Correlación con la ejecución contable en BD."
              }
            }
          }
        }
      },
      "HandlerError": {
        "type": "object",
        "required": [
          "status",
          "error"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "error"
            ]
          },
          "error": {
            "type": "string"
          }
        }
      },
      "GatewayError": {
        "type": "object",
        "required": [
          "message"
        ],
        "properties": {
          "message": {
            "type": "string"
          }
        }
      }
    }
  }
}
