{
  "openapi": "3.1.0",
  "info": {
    "title": "Zig — API pública de eventos",
    "version": "1.0.0",
    "description": "API pública read-only do catálogo de eventos. Só leitura: não existe endpoint de compra, reserva ou pagamento. Para comprar, mande a pessoa (ou o agente) pra `url` do evento. Não requer autenticação e não expõe dado de usuário.\n\n## Versioning & deprecation policy\nThe API is versioned in the URL path (`/api/public/v1`). Breaking changes ship under a new path version (`/v2`) and never alter the `/v1` in use. A version is deprecated only via the `Deprecation` and `Sunset` (RFC 8594) HTTP response headers on its responses, and stays available through the window announced in `Sunset` before removal.\n\n_pt-BR:_ A versão é fixada no caminho (`/api/public/v1`). Mudanças incompatíveis entram numa nova versão de caminho (`/v2`), nunca alterando a `/v1` em uso. Ao aposentar uma versão, sinalizamos com os headers HTTP `Deprecation` e `Sunset` (RFC 8594) nas respostas dela, mantendo-a no ar durante a janela anunciada no `Sunset` antes da remoção.\n\n## Erros\nRespostas 4xx/5xx usam `application/problem+json` (RFC 9457) com um `code` estável, legível por máquina, e `title`/`detail` legíveis por humano. Veja o schema `Problem`."
  },
  "servers": [
    {
      "url": "https://zig.tickets/api/public/v1"
    }
  ],
  "paths": {
    "/events": {
      "get": {
        "operationId": "listEvents",
        "summary": "Lista e busca eventos do catálogo público",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Termo de busca. Sem ele, devolve a listagem padrão."
          },
          {
            "name": "city",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Filtra por cidade do evento."
          },
          {
            "name": "state",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Filtra por UF, ex.: SP."
          },
          {
            "name": "organization",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Filtra por slug do organizador."
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          },
          {
            "name": "per_page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "default": 20
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Página de eventos",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "required": [
                          "id",
                          "slug",
                          "name",
                          "url"
                        ],
                        "properties": {
                          "id": {
                            "type": "integer"
                          },
                          "slug": {
                            "type": "string"
                          },
                          "name": {
                            "type": "string"
                          },
                          "description": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "Pode conter HTML."
                          },
                          "status": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "Rótulo do upstream (ativo, encerrado, ...). Só vem em GET /events; null em GET /events/{slug}. Para disponibilidade, use is_closed, que vem nos dois."
                          },
                          "starts_at": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "Início do evento."
                          },
                          "ends_at": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "Fim do evento."
                          },
                          "timezone": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "Fuso do evento. Sem ele, starts_at/ends_at são ambíguos."
                          },
                          "is_online": {
                            "type": "boolean"
                          },
                          "is_closed": {
                            "type": "boolean"
                          },
                          "url": {
                            "type": "string",
                            "format": "uri",
                            "description": "Página do evento, pra onde mandar a pessoa comprar."
                          },
                          "images": {
                            "type": "object",
                            "properties": {
                              "banner": {
                                "type": [
                                  "string",
                                  "null"
                                ],
                                "format": "uri"
                              },
                              "thumbnail": {
                                "type": [
                                  "string",
                                  "null"
                                ],
                                "format": "uri"
                              }
                            }
                          },
                          "location": {
                            "type": [
                              "object",
                              "null"
                            ],
                            "properties": {
                              "name": {
                                "type": [
                                  "string",
                                  "null"
                                ]
                              },
                              "city": {
                                "type": [
                                  "string",
                                  "null"
                                ]
                              },
                              "state": {
                                "type": [
                                  "string",
                                  "null"
                                ]
                              },
                              "state_abbr": {
                                "type": [
                                  "string",
                                  "null"
                                ]
                              },
                              "formatted_address": {
                                "type": [
                                  "string",
                                  "null"
                                ]
                              },
                              "latitude": {
                                "type": [
                                  "string",
                                  "null"
                                ]
                              },
                              "longitude": {
                                "type": [
                                  "string",
                                  "null"
                                ]
                              }
                            }
                          },
                          "producer": {
                            "type": [
                              "object",
                              "null"
                            ],
                            "description": "Quem realiza o evento. Só vem em GET /events/{slug}; null na listagem.",
                            "properties": {
                              "name": {
                                "type": "string"
                              },
                              "slug": {
                                "type": "string"
                              }
                            }
                          }
                        }
                      }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "total": {
                          "type": "integer"
                        },
                        "per_page": {
                          "type": "integer"
                        },
                        "current_page": {
                          "type": "integer"
                        },
                        "last_page": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "Método não permitido",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "502": {
            "description": "Upstream indisponível",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/events/{slug}": {
      "get": {
        "operationId": "getEvent",
        "summary": "Detalhe de um evento pelo slug",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Evento",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "id",
                    "slug",
                    "name",
                    "url"
                  ],
                  "properties": {
                    "id": {
                      "type": "integer"
                    },
                    "slug": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "description": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Pode conter HTML."
                    },
                    "status": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Rótulo do upstream (ativo, encerrado, ...). Só vem em GET /events; null em GET /events/{slug}. Para disponibilidade, use is_closed, que vem nos dois."
                    },
                    "starts_at": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Início do evento."
                    },
                    "ends_at": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Fim do evento."
                    },
                    "timezone": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Fuso do evento. Sem ele, starts_at/ends_at são ambíguos."
                    },
                    "is_online": {
                      "type": "boolean"
                    },
                    "is_closed": {
                      "type": "boolean"
                    },
                    "url": {
                      "type": "string",
                      "format": "uri",
                      "description": "Página do evento, pra onde mandar a pessoa comprar."
                    },
                    "images": {
                      "type": "object",
                      "properties": {
                        "banner": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "uri"
                        },
                        "thumbnail": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "uri"
                        }
                      }
                    },
                    "location": {
                      "type": [
                        "object",
                        "null"
                      ],
                      "properties": {
                        "name": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "city": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "state": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "state_abbr": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "formatted_address": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "latitude": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "longitude": {
                          "type": [
                            "string",
                            "null"
                          ]
                        }
                      }
                    },
                    "producer": {
                      "type": [
                        "object",
                        "null"
                      ],
                      "description": "Quem realiza o evento. Só vem em GET /events/{slug}; null na listagem.",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "slug": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Slug ausente",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Evento não encontrado",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "405": {
            "description": "Método não permitido",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/agent/identity": {
      "post": {
        "operationId": "issueAnonymousAgentCredential",
        "summary": "Emite uma credencial anônima de agente",
        "description": "Identificador opaco para o agente ser reconhecido entre requisições (telemetria e, na borda, chave de rate limit). **Não concede acesso**: a API pública é aberta e continua aberta. Ações em nome de uma pessoa exigem o Bearer dela — veja /auth.md.",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "enum": [
                      "anonymous"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Credencial emitida",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "identity_type",
                    "credential_type",
                    "credential"
                  ],
                  "properties": {
                    "identity_type": {
                      "type": "string",
                      "enum": [
                        "anonymous"
                      ]
                    },
                    "credential_type": {
                      "type": "string"
                    },
                    "credential": {
                      "type": "string",
                      "description": "Envie em X-Agent-Credential."
                    },
                    "usage": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Tipo de identidade não suportado",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "405": {
            "description": "Método não permitido",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/health": {
      "get": {
        "operationId": "getHealth",
        "summary": "Liveness da camada pública",
        "responses": {
          "200": {
            "description": "OK"
          },
          "405": {
            "description": "Método não permitido",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Problem": {
        "type": "object",
        "description": "Erro no formato RFC 9457 (application/problem+json).",
        "required": [
          "type",
          "title",
          "status",
          "code"
        ],
        "properties": {
          "type": {
            "type": "string",
            "format": "uri",
            "description": "URI de referência do tipo do erro."
          },
          "title": {
            "type": "string",
            "description": "Resumo humano do tipo do erro."
          },
          "status": {
            "type": "integer",
            "description": "Código HTTP."
          },
          "code": {
            "type": "string",
            "description": "Código estável, legível por máquina."
          },
          "detail": {
            "type": "string",
            "description": "Mensagem humana específica desta ocorrência."
          },
          "error": {
            "type": "string",
            "description": "Compat com a v1 anterior — espelha `code`."
          }
        }
      }
    }
  }
}