{
  "openapi": "3.1.0",
  "info": {
    "title": "Uma Dica API",
    "version": "1.2.0",
    "description": "Curated events, shows and places in Brasília and the Federal District, Brazil. Use only what the API returns; credit 'Uma Dica'.",
    "contact": {
      "url": "https://api.umadica.com"
    },
    "termsOfService": "https://api.umadica.com/terms"
  },
  "servers": [
    {
      "url": "https://api.umadica.com"
    }
  ],
  "security": [
    {
      "apiKey": []
    }
  ],
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key"
      }
    },
    "schemas": {
      "Event": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "date": {
            "type": "string",
            "format": "date"
          },
          "end_date": {
            "type": "string",
            "format": "date"
          },
          "start_time": {
            "type": "string"
          },
          "venue": {
            "type": "string"
          },
          "neighbourhood": {
            "type": "string"
          },
          "region": {
            "type": "string"
          },
          "category": {
            "type": "string"
          },
          "price": {
            "type": "string"
          },
          "instagram": {
            "type": "string"
          },
          "lineup": {
            "type": "string"
          },
          "address": {
            "type": "string"
          },
          "tickets": {
            "type": "string"
          },
          "uau": {
            "type": "boolean",
            "description": "Has the Selo UAU!! ✅"
          },
          "links": {
            "type": "object",
            "properties": {
              "google_maps": {
                "type": "string",
                "format": "uri"
              },
              "website": {
                "type": "string",
                "format": "uri"
              },
              "instagram": {
                "type": "string",
                "format": "uri"
              },
              "tickets": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      },
      "Place": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "neighbourhood": {
            "type": "string"
          },
          "region": {
            "type": "string"
          },
          "category": {
            "type": "string"
          },
          "style": {
            "type": "string"
          },
          "price": {
            "type": "string"
          },
          "instagram": {
            "type": "string"
          },
          "address": {
            "type": "string"
          },
          "mentions": {
            "type": "integer"
          },
          "uau": {
            "type": "boolean"
          },
          "description": {
            "type": "object",
            "properties": {
              "pt": {
                "type": "string"
              },
              "en": {
                "type": "string"
              }
            }
          },
          "links": {
            "type": "object",
            "properties": {
              "google_maps": {
                "type": "string",
                "format": "uri"
              },
              "website": {
                "type": "string",
                "format": "uri"
              },
              "instagram": {
                "type": "string",
                "format": "uri"
              },
              "tickets": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "const": false
          },
          "error": {
            "type": "string"
          }
        }
      }
    }
  },
  "paths": {
    "/v1": {
      "post": {
        "operationId": "umadica",
        "summary": "Search Uma Dica (events, places, summary, usage)",
        "description": "Set action to search_events, search_places, summary or usage. Dates are YYYY-MM-DD; work out relative dates from the 'today' field in any response.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "action"
                ],
                "properties": {
                  "action": {
                    "type": "string",
                    "enum": [
                      "search_events",
                      "search_places",
                      "summary",
                      "usage"
                    ]
                  },
                  "category": {
                    "type": "string",
                    "description": "Type of thing, English or Portuguese (jazz, samba, café, padaria, boteco, vegan, feira, kids…)"
                  },
                  "q": {
                    "type": "string",
                    "description": "Free text across names, venues, line-ups and styles"
                  },
                  "region": {
                    "type": "string",
                    "description": "Neighbourhood, DF region, code (SQN, SCLN) or zone (Centro, Lagos, Oeste, Norte, Sul, Leste)"
                  },
                  "limit": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 50
                  },
                  "from": {
                    "type": "string",
                    "format": "date",
                    "description": "search_events only; default today"
                  },
                  "to": {
                    "type": "string",
                    "format": "date",
                    "description": "search_events only; default from + 7 days"
                  }
                }
              },
              "examples": {
                "jazz": {
                  "value": {
                    "action": "search_events",
                    "category": "jazz",
                    "from": "2026-10-23",
                    "to": "2026-10-25"
                  }
                },
                "cafes": {
                  "value": {
                    "action": "search_places",
                    "category": "café",
                    "region": "Asa Norte",
                    "limit": 5
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Results",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "today": {
                      "type": "string",
                      "format": "date"
                    },
                    "plan": {
                      "type": "string"
                    },
                    "count": {
                      "type": "integer"
                    },
                    "events": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Event"
                      }
                    },
                    "places": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Place"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid key"
          },
          "403": {
            "description": "Not in your plan"
          },
          "429": {
            "description": "Rate limit or monthly quota"
          }
        }
      }
    },
    "/v1/plans": {
      "get": {
        "operationId": "listPlans",
        "summary": "List plans and prices",
        "security": [],
        "responses": {
          "200": {
            "description": "Plans"
          }
        }
      }
    },
    "/v1/signup": {
      "post": {
        "operationId": "signup",
        "summary": "Get a free key by email",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "name": {
                    "type": "string"
                  },
                  "company": {
                    "type": "string"
                  },
                  "use_case": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Key emailed"
          },
          "400": {
            "description": "Invalid email or too many sign-ups"
          }
        }
      }
    },
    "/v1/billing/checkout": {
      "post": {
        "operationId": "checkout",
        "summary": "Upgrade your key to a paid plan; returns a pay_url",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "plan"
                ],
                "properties": {
                  "plan": {
                    "type": "string",
                    "enum": [
                      "gringo",
                      "pro",
                      "business"
                    ]
                  },
                  "tax_id": {
                    "type": "string",
                    "description": "CPF or CNPJ, numbers only (Brazil)"
                  },
                  "name": {
                    "type": "string"
                  },
                  "method": {
                    "type": "string",
                    "enum": [
                      "PIX",
                      "BOLETO",
                      "CREDIT_CARD"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Checkout created"
          },
          "400": {
            "description": "Missing tax_id or bad plan"
          },
          "503": {
            "description": "Paid plans not open yet"
          }
        }
      }
    },
    "/v1/billing/status": {
      "post": {
        "operationId": "billingStatus",
        "summary": "Your plan and subscription",
        "responses": {
          "200": {
            "description": "Status"
          }
        }
      }
    },
    "/v1/billing/cancel": {
      "post": {
        "operationId": "cancel",
        "summary": "Cancel (send confirm: yes); plan stays until the paid month ends",
        "responses": {
          "200": {
            "description": "Canceled or confirmation needed"
          }
        }
      }
    },
    "/v1/keys/rotate": {
      "post": {
        "operationId": "rotateKey",
        "summary": "Replace your key; the old one stops at once",
        "responses": {
          "200": {
            "description": "New key (also emailed)"
          },
          "401": {
            "description": "Invalid key"
          }
        }
      }
    }
  }
}