{
  "openapi": "3.1.0",
  "info": {
    "title": "Multabot API",
    "version": "1.0.0",
    "description": "API REST para consultar infracciones, crear monitores y recibir eventos de Multabot. El acceso requiere una cuenta empresarial habilitada por Multabot.",
    "contact": {
      "name": "Soporte de Multabot",
      "url": "https://multabot.com.ar/contacto",
      "email": "contacto@multabot.com.ar"
    }
  },
  "servers": [
    {
      "url": "https://api.multabot.com.ar",
      "description": "Producción"
    }
  ],
  "externalDocs": {
    "description": "Portal de desarrolladores de Multabot",
    "url": "https://multabot.com.ar/developers"
  },
  "tags": [
    {
      "name": "Infracciones",
      "description": "Consultas normalizadas de infracciones disponibles en las fuentes consultadas."
    },
    {
      "name": "Monitores",
      "description": "Seguimiento periódico de patentes y notificaciones de novedades."
    },
    {
      "name": "Webhooks",
      "description": "Configuración de destinos para eventos de monitoreo."
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "paths": {
    "/v1/infracciones": {
      "get": {
        "tags": ["Infracciones"],
        "operationId": "listInfracciones",
        "summary": "Consultar infracciones",
        "description": "Busca infracciones por patente o documento. La respuesta incluye la fecha de consulta y la jurisdicción de cada resultado.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Plate"
          },
          {
            "$ref": "#/components/parameters/Document"
          },
          {
            "$ref": "#/components/parameters/Jurisdiction"
          },
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/PageSize"
          }
        ],
        "responses": {
          "200": {
            "description": "Resultados de infracciones",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InfractionsResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/monitores": {
      "get": {
        "tags": ["Monitores"],
        "operationId": "listMonitores",
        "summary": "Listar monitores",
        "description": "Devuelve los monitores habilitados para la cuenta autenticada.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/PageSize"
          }
        ],
        "responses": {
          "200": {
            "description": "Monitores de la cuenta",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MonitorsResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "post": {
        "tags": ["Monitores"],
        "operationId": "createMonitor",
        "summary": "Crear un monitor",
        "description": "Crea un seguimiento periódico para una patente y devuelve el monitor creado.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateMonitorRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Monitor creado",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Monitor"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/monitores/{monitorId}": {
      "get": {
        "tags": ["Monitores"],
        "operationId": "getMonitor",
        "summary": "Obtener un monitor",
        "description": "Devuelve el estado y la configuración de un monitor de la cuenta autenticada.",
        "parameters": [
          {
            "$ref": "#/components/parameters/MonitorId"
          }
        ],
        "responses": {
          "200": {
            "description": "Monitor encontrado",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Monitor"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/webhooks": {
      "post": {
        "tags": ["Webhooks"],
        "operationId": "createWebhookEndpoint",
        "summary": "Registrar un webhook",
        "description": "Registra el destino HTTPS al que Multabot enviará eventos de monitoreo para la cuenta.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateWebhookRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Webhook registrado",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookEndpoint"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "API key"
      }
    },
    "parameters": {
      "Plate": {
        "name": "plate",
        "in": "query",
        "description": "Patente o dominio del vehículo. Usá plate o document.",
        "required": false,
        "schema": {
          "type": "string",
          "minLength": 3,
          "maxLength": 12,
          "examples": ["AB123CD"]
        }
      },
      "Document": {
        "name": "document",
        "in": "query",
        "description": "DNI o documento de la persona consultada. Usá document o plate.",
        "required": false,
        "schema": {
          "type": "string",
          "minLength": 6,
          "maxLength": 20,
          "examples": ["30123456"]
        }
      },
      "Jurisdiction": {
        "name": "jurisdiction",
        "in": "query",
        "description": "Filtra por el slug de una jurisdicción.",
        "required": false,
        "schema": {
          "type": "string",
          "pattern": "^[a-z0-9-]+$"
        }
      },
      "Page": {
        "name": "page",
        "in": "query",
        "description": "Página comenzando en 1.",
        "required": false,
        "schema": {
          "type": "integer",
          "minimum": 1,
          "default": 1
        }
      },
      "PageSize": {
        "name": "pageSize",
        "in": "query",
        "description": "Cantidad de resultados por página.",
        "required": false,
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 100,
          "default": 25
        }
      },
      "MonitorId": {
        "name": "monitorId",
        "in": "path",
        "description": "Identificador único del monitor.",
        "required": true,
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      }
    },
    "headers": {
      "RateLimitLimit": {
        "description": "Límite de solicitudes de la ventana actual.",
        "schema": {
          "type": "integer",
          "minimum": 0
        }
      },
      "RateLimitRemaining": {
        "description": "Solicitudes restantes en la ventana actual.",
        "schema": {
          "type": "integer",
          "minimum": 0
        }
      },
      "RateLimitReset": {
        "description": "Segundos hasta el reinicio de la ventana actual.",
        "schema": {
          "type": "integer",
          "minimum": 0
        }
      },
      "RetryAfter": {
        "description": "Segundos que el cliente debe esperar antes de reintentar.",
        "schema": {
          "type": "integer",
          "minimum": 0
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "La solicitud no cumple el esquema requerido.",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Falta un token Bearer válido.",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      },
      "NotFound": {
        "description": "No existe el recurso solicitado.",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      },
      "TooManyRequests": {
        "description": "Se alcanzó el límite de solicitudes. Esperá el tiempo indicado y reintentá.",
        "headers": {
          "RateLimit-Limit": {
            "$ref": "#/components/headers/RateLimitLimit"
          },
          "RateLimit-Remaining": {
            "$ref": "#/components/headers/RateLimitRemaining"
          },
          "RateLimit-Reset": {
            "$ref": "#/components/headers/RateLimitReset"
          },
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      }
    },
    "schemas": {
      "Infraction": {
        "type": "object",
        "required": ["id", "jurisdiction", "status", "checkedAt"],
        "properties": {
          "id": {
            "type": "string",
            "description": "Identificador de la infracción en Multabot."
          },
          "plate": {
            "type": "string"
          },
          "document": {
            "type": "string"
          },
          "jurisdiction": {
            "type": "string",
            "description": "Slug de la jurisdicción que informó el resultado."
          },
          "status": {
            "type": "string",
            "enum": ["pending", "paid", "dismissed", "unknown"]
          },
          "issuedAt": {
            "type": ["string", "null"],
            "format": "date"
          },
          "dueDate": {
            "type": ["string", "null"],
            "format": "date"
          },
          "amount": {
            "type": ["number", "null"],
            "minimum": 0
          },
          "currency": {
            "type": ["string", "null"],
            "example": "ARS"
          },
          "sourceUrl": {
            "type": ["string", "null"],
            "format": "uri"
          },
          "checkedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "InfractionsResponse": {
        "type": "object",
        "required": ["data", "meta"],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Infraction"
            }
          },
          "meta": {
            "$ref": "#/components/schemas/Pagination"
          }
        }
      },
      "Pagination": {
        "type": "object",
        "required": ["page", "pageSize", "total"],
        "properties": {
          "page": {
            "type": "integer",
            "minimum": 1
          },
          "pageSize": {
            "type": "integer",
            "minimum": 1
          },
          "total": {
            "type": "integer",
            "minimum": 0
          }
        }
      },
      "CreateMonitorRequest": {
        "type": "object",
        "required": ["plate"],
        "properties": {
          "plate": {
            "type": "string",
            "minLength": 3,
            "maxLength": 12
          },
          "jurisdictions": {
            "type": "array",
            "items": {
              "type": "string",
              "pattern": "^[a-z0-9-]+$"
            }
          },
          "webhookId": {
            "type": ["string", "null"],
            "format": "uuid"
          }
        }
      },
      "Monitor": {
        "type": "object",
        "required": ["id", "plate", "status", "createdAt"],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "plate": {
            "type": "string"
          },
          "jurisdictions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "status": {
            "type": "string",
            "enum": ["active", "paused", "cancelled"]
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "lastCheckedAt": {
            "type": ["string", "null"],
            "format": "date-time"
          }
        }
      },
      "MonitorsResponse": {
        "type": "object",
        "required": ["data", "meta"],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Monitor"
            }
          },
          "meta": {
            "$ref": "#/components/schemas/Pagination"
          }
        }
      },
      "CreateWebhookRequest": {
        "type": "object",
        "required": ["url", "events"],
        "properties": {
          "url": {
            "type": "string",
            "format": "uri",
            "pattern": "^https://"
          },
          "events": {
            "type": "array",
            "minItems": 1,
            "items": {
              "type": "string",
              "enum": ["monitor.updated", "infraction.created"]
            }
          }
        }
      },
      "WebhookEndpoint": {
        "type": "object",
        "required": ["id", "url", "events", "createdAt"],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Problem": {
        "type": "object",
        "required": ["type", "title", "status", "detail"],
        "properties": {
          "type": {
            "type": "string",
            "format": "uri-reference"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer",
            "minimum": 400,
            "maximum": 599
          },
          "detail": {
            "type": "string"
          },
          "instance": {
            "type": "string",
            "format": "uri-reference"
          }
        }
      }
    }
  }
}
