{
  "openapi": "3.1.0",
  "info": {
    "title": "Jurify Cert API",
    "version": "1.0.0",
    "summary": "Certificado digital A1 do escritório na nuvem: login em tribunais, 2FA e assinatura de PDF por usuário, com auditoria.",
    "description": "API que a extensão do Chrome e os robôs (RPA) do escritório usam. Um agente de IA opera em nome de um escritório com um usuário criado pelo administrador no painel (https://cert.jurify.com.br/usuarios), com as permissões que ele escolheu (podeLogar, podeAssinar) e só nos certificados liberados. Toda chamada é auditada. A chave privada e os segredos TOTP nunca saem do servidor. Guia para agentes: https://cert.jurify.com.br/agentes.",
    "contact": {
      "name": "Suporte Jurify",
      "email": "suporte@jurify.com.br",
      "url": "https://cert.jurify.com.br/agentes"
    }
  },
  "externalDocs": {
    "description": "Guia para agentes de IA (A2A, llms.txt, exemplos)",
    "url": "https://cert.jurify.com.br/agentes"
  },
  "servers": [
    {
      "url": "https://cert.jurify.com.br/api/v1"
    }
  ],
  "tags": [
    {
      "name": "Público",
      "description": "Sem login"
    },
    {
      "name": "Sessão",
      "description": "Token do usuário do escritório"
    },
    {
      "name": "Tribunais",
      "description": "Login em portais de tribunais"
    },
    {
      "name": "Assinatura",
      "description": "Assinatura de documentos com o certificado"
    }
  ],
  "components": {
    "securitySchemes": {
      "bearer": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "Token de POST /ext/login, válido por 12 h. Também aceito no header X-Certjur-Token."
      }
    },
    "responses": {
      "Erro": {
        "description": "Erro de regra ou permissão. Mensagens de permissão não devem ser repetidas: quem decide é o administrador.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Erro"
            }
          }
        }
      },
      "NaoAutenticado": {
        "description": "Token ausente, vencido ou usuário inativado. Faça login de novo.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Erro"
            }
          }
        }
      }
    },
    "schemas": {
      "Erro": {
        "type": "object",
        "properties": {
          "statusCode": {
            "type": "integer"
          },
          "code": {
            "type": "string"
          },
          "message": {
            "type": "string",
            "examples": [
              "Você não tem permissão para usar este certificado"
            ]
          }
        }
      },
      "Usuario": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "nome": {
            "type": "string"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "papel": {
            "type": "string",
            "enum": [
              "ADMIN",
              "OPERADOR"
            ]
          },
          "podeLogar": {
            "type": "boolean"
          },
          "podeAssinar": {
            "type": "boolean"
          },
          "escritorio": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "nome": {
                "type": "string"
              },
              "cnpj": {
                "type": "string"
              },
              "plano": {
                "type": "string",
                "enum": [
                  "TRIAL",
                  "ATIVO",
                  "SUSPENSO"
                ]
              },
              "trialAte": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          }
        }
      },
      "Certificado": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "titular": {
            "type": "string"
          },
          "apelido": {
            "type": [
              "string",
              "null"
            ]
          },
          "tipo": {
            "type": "string",
            "description": "e-CPF ou e-CNPJ"
          },
          "documentoMascarado": {
            "type": "string"
          },
          "validoAte": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "diasRestantes": {
            "type": [
              "integer",
              "null"
            ]
          },
          "temOtp": {
            "type": "boolean",
            "description": "Tem o 2FA da PDPJ (usado por todos os PJe)"
          }
        }
      },
      "Portal": {
        "type": "object",
        "properties": {
          "chave": {
            "type": "string",
            "examples": [
              "tjpr",
              "trt2",
              "tjsp-eproc"
            ],
            "description": "Identificador usado em portal= e chave="
          },
          "nome": {
            "type": "string"
          },
          "sigla": {
            "type": "string"
          },
          "uf": {
            "type": "string"
          },
          "sistema": {
            "type": "string",
            "enum": [
              "PJe",
              "JPe",
              "eproc",
              "e-SAJ",
              "Projudi"
            ]
          },
          "grau": {
            "type": "string",
            "enum": [
              "1g",
              "2g",
              "rec",
              "sup",
              "un"
            ]
          },
          "estrategia": {
            "type": "string",
            "enum": [
              "pjeoffice",
              "eproc",
              "esaj",
              "projudi"
            ],
            "description": "pjeoffice = entra com o certificado; as demais = login e senha do portal mais 2FA"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "rotulo": {
            "type": "string"
          },
          "obs": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "validado",
              "mapeado",
              "indisponivel",
              "nao_sondado"
            ]
          },
          "contaDe": {
            "type": "string",
            "description": "Portal cuja conta e 2FA este reutiliza; vazio = o próprio"
          }
        }
      }
    }
  },
  "paths": {
    "/saude": {
      "get": {
        "tags": [
          "Público"
        ],
        "operationId": "saude",
        "summary": "Estado do serviço",
        "responses": {
          "200": {
            "description": "ok",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "versao": {
                      "type": "string"
                    },
                    "db": {
                      "type": "string"
                    },
                    "signer": {
                      "type": "string"
                    },
                    "hora": {
                      "type": "string",
                      "format": "date-time"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/publico/portais": {
      "get": {
        "tags": [
          "Público"
        ],
        "operationId": "listarPortaisPublico",
        "summary": "Catálogo de portais de tribunais, com status de validação",
        "description": "O mesmo catálogo da extensão, sem login. Use para responder se o Jurify Cert cobre um tribunal.",
        "responses": {
          "200": {
            "description": "Lista de portais",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Portal"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/a2a": {
      "post": {
        "tags": [
          "Público"
        ],
        "operationId": "a2a",
        "summary": "Agente A2A (JSON-RPC 2.0, método message/send)",
        "description": "Agent Card em https://cert.jurify.com.br/.well-known/agent-card.json. Skills: cobertura-tribunais, produto, integracao. Responde Message (texto + dados), nunca Task.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              },
              "example": {
                "jsonrpc": "2.0",
                "id": 1,
                "method": "message/send",
                "params": {
                  "message": {
                    "role": "user",
                    "messageId": "m-1",
                    "parts": [
                      {
                        "kind": "text",
                        "text": "Funciona no TJPR?"
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Resposta JSON-RPC (result ou error)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/ext/login": {
      "post": {
        "tags": [
          "Sessão"
        ],
        "operationId": "login",
        "summary": "Troca e-mail e senha do usuário do escritório por um token de 12 h",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email",
                  "senha"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "senha": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Token e usuário",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "token": {
                      "type": "string"
                    },
                    "usuario": {
                      "$ref": "#/components/schemas/Usuario"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NaoAutenticado"
          }
        }
      }
    },
    "/ext/me": {
      "get": {
        "tags": [
          "Sessão"
        ],
        "operationId": "eu",
        "summary": "Usuário do token e suas permissões",
        "security": [
          {
            "bearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "Usuário",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Usuario"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NaoAutenticado"
          }
        }
      }
    },
    "/ext/certificados": {
      "get": {
        "tags": [
          "Sessão"
        ],
        "operationId": "listarCertificados",
        "summary": "Certificados que o usuário pode usar",
        "security": [
          {
            "bearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "Certificados",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Certificado"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/NaoAutenticado"
          }
        }
      }
    },
    "/ext/portais": {
      "get": {
        "tags": [
          "Tribunais"
        ],
        "operationId": "listarPortais",
        "summary": "Catálogo de portais (autenticado)",
        "security": [
          {
            "bearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "Portais",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Portal"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/ext/otp": {
      "get": {
        "tags": [
          "Tribunais"
        ],
        "operationId": "codigo2fa",
        "summary": "Código 2FA (TOTP) do portal, gerado no servidor",
        "description": "Chame só quando a tela do código estiver visível. Se expiraEm < 5, espere a próxima janela de 30 s: os tribunais recusam reuso do mesmo código. chave=pdpj vale para todos os PJe. Gera evento OTP na auditoria.",
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "name": "certificadoId",
            "in": "query",
            "required": true,
            "description": "Id do certificado",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "chave",
            "in": "query",
            "required": false,
            "description": "Chave do portal ou do 2FA (pdpj, tjpr, tjsp-eproc...)",
            "schema": {
              "type": "string"
            },
            "example": "pdpj"
          }
        ],
        "responses": {
          "200": {
            "description": "Código",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "codigo": {
                      "type": "string",
                      "examples": [
                        "492013"
                      ]
                    },
                    "expiraEm": {
                      "type": "integer",
                      "description": "Segundos até a janela virar"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro"
          },
          "401": {
            "$ref": "#/components/responses/NaoAutenticado"
          }
        }
      }
    },
    "/ext/credencial": {
      "get": {
        "tags": [
          "Tribunais"
        ],
        "operationId": "credencialPortal",
        "summary": "Login e senha do portal (eproc, e-SAJ, Projudi)",
        "description": "Para portais cuja estrategia não é pjeoffice. Exige podeLogar e acesso ao certificado. Gera evento LOGIN_TRIBUNAL na auditoria. Use a senha só para preencher o formulário do tribunal; nunca a exiba nem a guarde.",
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "name": "certificadoId",
            "in": "query",
            "required": true,
            "description": "Id do certificado",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "portal",
            "in": "query",
            "required": true,
            "description": "Chave do portal",
            "schema": {
              "type": "string"
            },
            "example": "tjsp-eproc"
          }
        ],
        "responses": {
          "200": {
            "description": "Credencial",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "login": {
                      "type": "string"
                    },
                    "senha": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro"
          },
          "401": {
            "$ref": "#/components/responses/NaoAutenticado"
          }
        }
      }
    },
    "/ext/assinar-pdf": {
      "post": {
        "tags": [
          "Assinatura"
        ],
        "operationId": "assinarPdf",
        "summary": "Assina um PDF com o certificado (PAdES)",
        "description": "Exige podeAssinar. Até 50 MB. O PDF não é guardado após a resposta. Gera evento ASSINATURA_PDF na auditoria.",
        "security": [
          {
            "bearer": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "arquivo",
                  "certificadoId"
                ],
                "properties": {
                  "arquivo": {
                    "type": "string",
                    "format": "binary"
                  },
                  "certificadoId": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "motivo": {
                    "type": "string",
                    "maxLength": 200
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "PDF assinado",
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro"
          },
          "401": {
            "$ref": "#/components/responses/NaoAutenticado"
          }
        }
      }
    }
  }
}
