{
  "openapi": "3.0.3",
  "info": {
    "title": "Tudonuma — API de integração para imobiliárias",
    "version": "1.0.0",
    "description": "Publique e mantenha anúncios a partir do seu CRM. Autenticação por chave (Authorization: Bearer mk_...). Documentação narrativa em /api/v1/docs."
  },
  "servers": [{ "url": "https://tudonuma.com/api/v1" }],
  "security": [{ "apiKey": [] }],
  "components": {
    "securitySchemes": {
      "apiKey": { "type": "http", "scheme": "bearer", "bearerFormat": "mk_..." }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": { "error": { "type": "string" }, "message": { "type": "string" } },
        "required": ["error", "message"]
      },
      "ListingInput": {
        "type": "object",
        "properties": {
          "title": { "type": "string", "minLength": 3, "maxLength": 200 },
          "operation": { "type": "string", "enum": ["aluguel", "venda"] },
          "type": { "type": "string", "enum": ["apartamento", "studio", "casa", "loft", "coliving", "cobertura", "consultorio", "galpao", "comercial", "terreno", "terreno_comercial", "loja", "sala", "predio", "rural"] },
          "address": { "type": "string" },
          "neighborhood": { "type": "string" },
          "city": { "type": "string" },
          "uf": { "type": "string", "minLength": 2, "maxLength": 2 },
          "lat": { "type": "number" },
          "lng": { "type": "number" },
          "area_m2": { "type": "integer" },
          "bedrooms": { "type": "integer" },
          "bathrooms": { "type": "integer" },
          "parking": { "type": "integer" },
          "floor": { "type": "integer", "description": "0 = térreo" },
          "building_floors": { "type": "integer" },
          "price": { "type": "number", "description": "Em reais. Alternativa: price_cents." },
          "price_cents": { "type": "integer" },
          "condo": { "type": "number" },
          "condo_cents": { "type": "integer" },
          "iptu": { "type": "number" },
          "iptu_cents": { "type": "integer" },
          "description": { "type": "string", "maxLength": 8000 },
          "photos": { "type": "array", "items": { "type": "string", "format": "uri" }, "maxItems": 16 },
          "furnished": { "oneOf": [{ "type": "boolean" }, { "type": "string", "enum": ["no", "partial", "full"] }] },
          "pet_friendly": { "type": "boolean" },
          "internet": { "type": "boolean" },
          "amenities": { "type": "array", "items": { "type": "string" } },
          "tags": { "type": "array", "items": { "type": "string" } },
          "contact_phone": { "type": "string" },
          "show_whatsapp": { "type": "boolean" },
          "show_phone": { "type": "boolean" },
          "show_chat": { "type": "boolean" },
          "matricula": { "type": "string", "maxLength": 64 },
          "inscricao": { "type": "string", "maxLength": 64 },
          "owner_type": { "type": "string", "enum": ["owner", "agency"] },
          "available": { "type": "boolean" }
        }
      },
      "Listing": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "public_id": { "type": "string" },
          "external_id": { "type": "string" },
          "url": { "type": "string" },
          "status": { "type": "string", "enum": ["active", "paused", "pending_review", "rejected", "deleted"] },
          "moderation": { "type": "string", "enum": ["pending", "approved", "rejected"] },
          "moderation_note": { "type": "string" },
          "title": { "type": "string" },
          "operation": { "type": "string" },
          "type": { "type": "string" },
          "address": { "type": "string" },
          "neighborhood": { "type": "string" },
          "city": { "type": "string" },
          "uf": { "type": "string" },
          "lat": { "type": "number", "nullable": true },
          "lng": { "type": "number", "nullable": true },
          "area_m2": { "type": "integer" },
          "bedrooms": { "type": "integer" },
          "bathrooms": { "type": "integer" },
          "parking": { "type": "integer" },
          "price_cents": { "type": "integer" },
          "condo_cents": { "type": "integer" },
          "iptu_cents": { "type": "integer" },
          "description": { "type": "string" },
          "photos": { "type": "array", "items": { "type": "string" } },
          "matricula": { "type": "string" },
          "inscricao": { "type": "string" },
          "created_at": { "type": "string", "format": "date-time" },
          "updated_at": { "type": "string", "format": "date-time" },
          "created": { "type": "boolean" },
          "warnings": { "type": "array", "items": { "type": "string" } }
        }
      },
      "Webhook": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "url": { "type": "string" },
          "events": { "type": "array", "items": { "type": "string" } },
          "active": { "type": "boolean" },
          "created_at": { "type": "string" },
          "last_status": { "type": "integer", "nullable": true },
          "last_delivered_at": { "type": "string", "nullable": true },
          "failures": { "type": "integer" },
          "secret": { "type": "string", "description": "Só na criação." }
        }
      }
    },
    "responses": {
      "Error": { "description": "Erro", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
    }
  },
  "paths": {
    "/me": {
      "get": { "summary": "Quem sou eu", "responses": { "200": { "description": "Imobiliária, escopos e modo de moderação." }, "401": { "$ref": "#/components/responses/Error" } } }
    },
    "/listings": {
      "get": {
        "summary": "Lista os anúncios desta conta",
        "parameters": [
          { "name": "page", "in": "query", "schema": { "type": "integer", "minimum": 1 } },
          { "name": "status", "in": "query", "schema": { "type": "string", "enum": ["active", "paused", "rejected", "pending_review", "all"] } }
        ],
        "responses": { "200": { "description": "data, total, page, page_size", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Listing" } }, "total": { "type": "integer" }, "page": { "type": "integer" }, "page_size": { "type": "integer" } } } } } } }
      }
    },
    "/listings/batch": {
      "post": {
        "summary": "Cria/atualiza até 200 anúncios",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "listings": { "type": "array", "maxItems": 200, "items": { "allOf": [{ "type": "object", "properties": { "external_id": { "type": "string" } }, "required": ["external_id"] }, { "$ref": "#/components/schemas/ListingInput" }] } } }, "required": ["listings"] } } } },
        "responses": { "200": { "description": "ok, failed, results[]" }, "400": { "$ref": "#/components/responses/Error" } }
      }
    },
    "/listings/{external_id}": {
      "parameters": [{ "name": "external_id", "in": "path", "required": true, "schema": { "type": "string", "pattern": "^[A-Za-z0-9._:-]{1,100}$" } }],
      "get": { "summary": "Um anúncio", "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Listing" } } } }, "404": { "$ref": "#/components/responses/Error" } } },
      "put": {
        "summary": "Cria ou atualiza (upsert)",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ListingInput" } } } },
        "responses": { "200": { "description": "Atualizado", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Listing" } } } }, "201": { "description": "Criado", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Listing" } } } }, "400": { "$ref": "#/components/responses/Error" } }
      },
      "delete": { "summary": "Remove (exclusão lógica)", "responses": { "200": { "description": "OK" }, "404": { "$ref": "#/components/responses/Error" } } }
    },
    "/listings/{external_id}/status": {
      "parameters": [{ "name": "external_id", "in": "path", "required": true, "schema": { "type": "string" } }],
      "post": {
        "summary": "Pausa ou reativa",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "status": { "type": "string", "enum": ["active", "paused"] } }, "required": ["status"] } } } },
        "responses": { "200": { "description": "OK" }, "409": { "$ref": "#/components/responses/Error" } }
      }
    },
    "/webhooks": {
      "get": { "summary": "Lista webhooks", "responses": { "200": { "description": "data[], events[]" } } },
      "post": {
        "summary": "Cadastra um webhook",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "url": { "type": "string", "format": "uri" }, "events": { "type": "array", "items": { "type": "string", "enum": ["listing.created", "listing.updated", "listing.deleted", "listing.approved", "listing.rejected", "ping"] } } }, "required": ["url"] } } } },
        "responses": { "201": { "description": "Criado — inclui secret (uma única vez)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Webhook" } } } }, "400": { "$ref": "#/components/responses/Error" } }
      }
    },
    "/webhooks/{id}": {
      "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }],
      "delete": { "summary": "Remove um webhook", "responses": { "200": { "description": "OK" }, "404": { "$ref": "#/components/responses/Error" } } }
    }
  }
}
