{
  "openapi": "3.1.0",
  "info": {
    "title": "API do TrilhosAgora",
    "version": "1.0.0",
    "description": "Situação ao vivo e histórico oficial das linhas de metrô e trem de São Paulo, coletados a cada 30 segundos dos canais públicos das operadoras.\n\nUso não comercial gratuito, com crédito visível \"Dados: TrilhosAgora\" (o link para https://trilhosagora.com.br é bem-vindo, mas opcional). Para uso comercial (apps e produtos pagos, revenda, integração em serviços de empresas ou volume alto de requisições), entre em contato: contato@trilhosagora.com.br.",
    "contact": {
      "name": "TrilhosAgora",
      "email": "contato@trilhosagora.com.br",
      "url": "https://trilhosagora.com.br/desenvolvedores"
    },
    "termsOfService": "https://trilhosagora.com.br/desenvolvedores#termos"
  },
  "servers": [
    {
      "url": "https://api.trilhosagora.com.br"
    }
  ],
  "security": [
    {
      "chave": []
    },
    {
      "bearer": []
    }
  ],
  "tags": [
    {
      "name": "Status"
    },
    {
      "name": "Histórico"
    },
    {
      "name": "Estações"
    },
    {
      "name": "Comunidade"
    }
  ],
  "paths": {
    "/v1/status": {
      "get": {
        "tags": [
          "Status"
        ],
        "summary": "Situação atual de todas as linhas",
        "description": "Uma entrada por linha, na ordem de exibição do site. As operadoras são consultadas a cada 30 segundos e a resposta pode ser reaproveitada em cache por alguns segundos: normalmente o dado tem menos de 1 minuto. Veja \"Como os dados são atualizados\".",
        "x-rate-limit": "o da sua chave (60 requisições por minuto, por padrão)",
        "responses": {
          "200": {
            "description": "Situação das linhas.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "lines": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "linha": {
                            "type": "integer",
                            "description": "Número da linha. O Expresso Aeroporto usa 100.",
                            "example": 4
                          },
                          "nome": {
                            "type": "string",
                            "example": "Amarela"
                          },
                          "rotulo": {
                            "type": "string",
                            "description": "Nome pronto para exibir.",
                            "example": "Linha 4-Amarela"
                          },
                          "slug": {
                            "type": "string",
                            "description": "Endereço da página da linha: /saopaulo/linha/{slug}.",
                            "example": "4-amarela"
                          },
                          "sigla": {
                            "type": "string",
                            "description": "Texto do círculo da linha.",
                            "example": "4"
                          },
                          "cor": {
                            "type": "string",
                            "description": "Cor oficial da linha (hex).",
                            "example": "#ffd200"
                          },
                          "status": {
                            "type": "string",
                            "description": "Situação informada pela operadora.",
                            "example": "Operação Normal"
                          },
                          "descricao": {
                            "type": "string",
                            "description": "Detalhe da operadora (pode vir vazio).",
                            "example": ""
                          },
                          "operadora": {
                            "type": "string",
                            "example": "Motiva"
                          },
                          "atualizado_em": {
                            "type": "string",
                            "format": "date-time",
                            "description": "Horário que a própria operadora informa para a situação. Não é o horário da coleta: pode ficar parado por horas se a operadora não atualiza o boletim.",
                            "example": "2026-10-28T09:45:05-03:00"
                          },
                          "desde": {
                            "type": "string",
                            "format": "date-time",
                            "nullable": true,
                            "description": "Quando o TrilhosAgora observou o início da situação atual.",
                            "example": "2026-10-28T04:41:57-03:00"
                          },
                          "desde_confirmado": {
                            "type": "boolean",
                            "description": "false quando \"desde\" é só o início do monitoramento, não uma mudança observada.",
                            "example": true
                          }
                        }
                      }
                    },
                    "fetched_at": {
                      "type": "string",
                      "format": "date-time",
                      "description": "Quando o TrilhosAgora leu a coleta mais recente para montar esta resposta (UTC)."
                    },
                    "stale": {
                      "type": "boolean",
                      "description": "true quando a leitura mais recente falhou e esta resposta repete a anterior (até 2 minutos)."
                    }
                  }
                },
                "example": {
                  "lines": [
                    {
                      "linha": 4,
                      "nome": "Amarela",
                      "rotulo": "Linha 4-Amarela",
                      "slug": "4-amarela",
                      "sigla": "4",
                      "cor": "#ffd200",
                      "status": "Operação Normal",
                      "descricao": "",
                      "operadora": "Motiva",
                      "atualizado_em": "2026-10-28T09:45:05-03:00",
                      "desde": "2026-10-28T04:41:57-03:00",
                      "desde_confirmado": true
                    }
                  ],
                  "fetched_at": "2026-10-28T12:45:20.000Z",
                  "stale": false
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido."
          },
          "503": {
            "description": "Status temporariamente indisponível."
          }
        }
      }
    },
    "/v1/history": {
      "get": {
        "tags": [
          "Histórico"
        ],
        "summary": "Ocorrências oficiais de uma linha nos últimos 7 dias",
        "description": "Situações fora da operação normal (velocidade reduzida, paralisação, atividade programada...), da mais recente para a mais antiga. \"fim_em\" nulo indica ocorrência em andamento.",
        "x-rate-limit": "o da sua chave (60 requisições por minuto, por padrão)",
        "parameters": [
          {
            "name": "line",
            "in": "query",
            "required": true,
            "description": "Número da linha (Expresso Aeroporto: 100).",
            "schema": {
              "type": "integer",
              "example": 9
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Ocorrências do período.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "days": {
                      "type": "integer"
                    },
                    "events": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "integer"
                          },
                          "situacao": {
                            "type": "string"
                          },
                          "descricao": {
                            "type": "string"
                          },
                          "inicio_em": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "fim_em": {
                            "type": "string",
                            "format": "date-time",
                            "nullable": true
                          },
                          "atualizado_em": {
                            "type": "string",
                            "format": "date-time",
                            "nullable": true
                          }
                        }
                      }
                    }
                  }
                },
                "example": {
                  "events": [
                    {
                      "id": 57,
                      "situacao": "Velocidade Reduzida",
                      "descricao": "Devido a alagamento na região de Santo Amaro, circulação com velocidade reduzida.",
                      "inicio_em": "2026-10-25T17:12:04-03:00",
                      "fim_em": "2026-10-25T18:40:31-03:00",
                      "atualizado_em": "2026-10-25T17:10:00-03:00"
                    }
                  ],
                  "days": 7
                }
              }
            }
          },
          "400": {
            "description": "Linha inválida."
          },
          "429": {
            "description": "Limite de requisições excedido."
          }
        }
      }
    },
    "/v1/stations": {
      "get": {
        "tags": [
          "Estações"
        ],
        "summary": "Estações de uma linha",
        "description": "Estações na sequência cadastrada da linha. Cada estação tem página própria em /saopaulo/estacao/{slug}.",
        "parameters": [
          {
            "name": "line",
            "in": "query",
            "required": true,
            "description": "Número da linha (Expresso Aeroporto: 100).",
            "schema": {
              "type": "integer",
              "example": 4
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Estações da linha.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "name": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "name": "Luz"
                    },
                    {
                      "name": "República"
                    },
                    {
                      "name": "Higienópolis-Mackenzie"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Linha inválida."
          }
        }
      }
    },
    "/v1/reports": {
      "get": {
        "tags": [
          "Comunidade"
        ],
        "summary": "Possíveis anomalias relatadas por passageiros",
        "description": "Linhas em que vários passageiros relataram problema nos últimos minutos enquanto a operadora informa operação normal. Não é informação oficial.",
        "x-rate-limit": "o da sua chave (60 requisições por minuto, por padrão)",
        "responses": {
          "200": {
            "description": "Anomalias ativas.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "anomalies": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    },
                    "threshold": {
                      "type": "integer",
                      "description": "Relatos necessários para gerar uma anomalia."
                    },
                    "windowMinutes": {
                      "type": "integer",
                      "description": "Janela considerada, em minutos."
                    }
                  }
                },
                "example": {
                  "anomalies": [],
                  "threshold": 3,
                  "windowMinutes": 15
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "chave": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "Chave gratuita, gerada em https://trilhosagora.com.br/desenvolvedores/painel com login do GitHub."
      },
      "bearer": {
        "type": "http",
        "scheme": "bearer",
        "description": "A mesma chave em Authorization: Bearer."
      }
    }
  }
}