{
  "openapi": "3.0.3",
  "info": {
    "title": "CDTEC IF · API para clientes",
    "version": "1.0.0",
    "description": "API de **solo lectura** para leer los datos de tus campos desde tus propios sistemas (ERP, BI, planillas). Autenticación con la llave en `X-Api-Key` o `Authorization: Bearer`. Respuestas `{ data, paginacion? }`; errores `{ error: { codigo, mensaje } }`. Rangos de hasta 31 días (7 por hora) y hasta 1000 filas por página. Guía completa, ejemplos y términos en https://desarrolladores.cdtecif.cl.",
    "termsOfService": "https://desarrolladores.cdtecif.cl/terminos.html",
    "contact": {
      "name": "CDTEC IF",
      "email": "departamentoid@cdtec.cl",
      "url": "https://desarrolladores.cdtecif.cl"
    }
  },
  "servers": [
    {
      "url": "https://api.cdtecif.cl/v1",
      "description": "Producción"
    },
    {
      "url": "https://app.cdtecif.cl/api/v1",
      "description": "Alias en app.cdtecif.cl"
    },
    {
      "url": "/api/v1",
      "description": "Este servidor"
    }
  ],
  "tags": [
    {
      "name": "Cuenta",
      "description": "La cuenta a la que pertenece la llave"
    },
    {
      "name": "Campos",
      "description": "Campos, sectores y equipos"
    },
    {
      "name": "Lecturas",
      "description": "Lecturas de sensores agregadas por hora o por día"
    },
    {
      "name": "Clima",
      "description": "Estaciones de clima y sus variables"
    },
    {
      "name": "Riego",
      "description": "Riegos registrados (programados y manuales)"
    }
  ],
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Api-Key",
        "description": "La llave completa (`cdtec_<prefijo>_<secreto>`), generada en Mi cuenta › API"
      },
      "bearer": {
        "type": "http",
        "scheme": "bearer",
        "description": "La misma llave como token Bearer (alternativa a X-Api-Key)"
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "codigo",
              "mensaje"
            ],
            "properties": {
              "codigo": {
                "type": "string",
                "enum": [
                  "no_autenticado",
                  "parametros_invalidos",
                  "no_encontrado",
                  "metodo_no_permitido",
                  "demasiadas_peticiones",
                  "error_interno",
                  "no_disponible"
                ]
              },
              "mensaje": {
                "type": "string"
              }
            }
          }
        },
        "example": {
          "error": {
            "codigo": "no_autenticado",
            "mensaje": "Llave de API inválida o ausente."
          }
        }
      },
      "Paginacion": {
        "type": "object",
        "required": [
          "siguienteCursor"
        ],
        "properties": {
          "siguienteCursor": {
            "type": "string",
            "nullable": true,
            "description": "Cursor opaco de la página siguiente; null si no hay más. Se repite la misma consulta agregando `cursor=`."
          }
        }
      },
      "Cuenta": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^[a-f0-9]{24}$",
            "example": "66f1c0a2b3d4e5f6a7b8c9d0"
          },
          "nombre": {
            "type": "string",
            "nullable": true,
            "example": "Agrícola Los Robles"
          },
          "cantidadCampos": {
            "type": "integer",
            "example": 3
          },
          "llave": {
            "type": "object",
            "properties": {
              "nombre": {
                "type": "string",
                "example": "Integración ERP"
              },
              "prefijo": {
                "type": "string",
                "example": "3f9a1c2e"
              },
              "scopes": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "example": [
                  "lectura"
                ]
              },
              "expiraEn": {
                "type": "string",
                "format": "date-time",
                "nullable": true
              }
            }
          }
        }
      },
      "Campo": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^[a-f0-9]{24}$",
            "example": "66f1c0a2b3d4e5f6a7b8c9d0"
          },
          "cuentaId": {
            "type": "string",
            "pattern": "^[a-f0-9]{24}$",
            "example": "66f1c0a2b3d4e5f6a7b8c9d0",
            "nullable": true
          },
          "nombre": {
            "type": "string",
            "nullable": true,
            "example": "Fundo Santa Rosa"
          },
          "ubicacion": {
            "type": "string",
            "nullable": true,
            "example": "Rancagua"
          },
          "zonaHoraria": {
            "type": "string",
            "nullable": true,
            "example": "America/Santiago"
          },
          "superficieTeorica": {
            "type": "number",
            "nullable": true,
            "description": "Hectáreas",
            "example": 12.5
          },
          "centro": {
            "type": "object",
            "nullable": true,
            "properties": {
              "lat": {
                "type": "number",
                "example": -34.1702
              },
              "lng": {
                "type": "number",
                "example": -70.7408
              }
            }
          },
          "zoom": {
            "type": "number",
            "nullable": true
          },
          "poligono": {
            "type": "array",
            "description": "Vértices en orden; vacío si no está dibujado.",
            "items": {
              "type": "object",
              "nullable": false,
              "properties": {
                "lat": {
                  "type": "number",
                  "example": -34.1702
                },
                "lng": {
                  "type": "number",
                  "example": -70.7408
                }
              }
            }
          },
          "creadoEn": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "actualizadoEn": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "Sector": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^[a-f0-9]{24}$",
            "example": "66f1c0a2b3d4e5f6a7b8c9d0"
          },
          "campoId": {
            "type": "string",
            "pattern": "^[a-f0-9]{24}$",
            "example": "66f1c0a2b3d4e5f6a7b8c9d0",
            "nullable": true
          },
          "sectorPadreId": {
            "type": "string",
            "pattern": "^[a-f0-9]{24}$",
            "example": "66f1c0a2b3d4e5f6a7b8c9d0",
            "nullable": true
          },
          "nombre": {
            "type": "string",
            "nullable": true,
            "example": "Sector 3"
          },
          "numero": {
            "type": "string",
            "nullable": true
          },
          "superficieTeorica": {
            "type": "number",
            "nullable": true,
            "description": "Hectáreas",
            "example": 3
          },
          "variedadId": {
            "type": "string",
            "pattern": "^[a-f0-9]{24}$",
            "example": "66f1c0a2b3d4e5f6a7b8c9d0",
            "nullable": true
          },
          "anioPlantacion": {
            "type": "number",
            "nullable": true,
            "example": 2018
          },
          "marcoPlantacion": {
            "type": "string",
            "nullable": true
          },
          "tipoSuelo": {
            "type": "string",
            "nullable": true
          },
          "telemetria": {
            "type": "string",
            "enum": [
              "wiseconn",
              "helius",
              "davis"
            ]
          },
          "riego": {
            "type": "object",
            "properties": {
              "tipo": {
                "type": "string",
                "nullable": true,
                "example": "Goteo"
              },
              "precipitacionTeorica": {
                "type": "number",
                "nullable": true,
                "description": "mm/h"
              },
              "precipitacionReal": {
                "type": "number",
                "nullable": true,
                "description": "mm/h"
              },
              "caudalEmisor": {
                "type": "number",
                "nullable": true,
                "description": "L/h",
                "example": 1.6
              },
              "distanciaEmisores": {
                "type": "number",
                "nullable": true,
                "description": "m"
              },
              "lineas": {
                "type": "number",
                "nullable": true
              },
              "distanciaHileras": {
                "type": "number",
                "nullable": true,
                "description": "m"
              },
              "emisoresPorHectarea": {
                "type": "number",
                "nullable": true
              },
              "distanciaPlantas": {
                "type": "number",
                "nullable": true,
                "description": "m"
              },
              "plantasPorHectarea": {
                "type": "number",
                "nullable": true
              }
            }
          },
          "poligono": {
            "type": "array",
            "description": "Vértices en orden; vacío si no está dibujado.",
            "items": {
              "type": "object",
              "nullable": false,
              "properties": {
                "lat": {
                  "type": "number",
                  "example": -34.1702
                },
                "lng": {
                  "type": "number",
                  "example": -70.7408
                }
              }
            }
          }
        }
      },
      "Equipo": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^[a-f0-9]{24}$",
            "example": "66f1c0a2b3d4e5f6a7b8c9d0"
          },
          "campoId": {
            "type": "string",
            "pattern": "^[a-f0-9]{24}$",
            "example": "66f1c0a2b3d4e5f6a7b8c9d0",
            "nullable": true
          },
          "sectorId": {
            "type": "string",
            "pattern": "^[a-f0-9]{24}$",
            "example": "66f1c0a2b3d4e5f6a7b8c9d0",
            "nullable": true
          },
          "nombre": {
            "type": "string",
            "nullable": true,
            "example": "Sonda 40 cm"
          },
          "tipo": {
            "type": "string",
            "nullable": true
          },
          "tipoSensor": {
            "type": "string",
            "nullable": true,
            "example": "Soil Moisture"
          },
          "esEstacion": {
            "type": "boolean"
          },
          "telemetria": {
            "type": "string",
            "enum": [
              "wiseconn",
              "helius",
              "davis"
            ]
          },
          "unidad": {
            "type": "string",
            "nullable": true
          },
          "estado": {
            "type": "string",
            "nullable": true,
            "example": "Operative"
          },
          "ultimaActividad": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "coordenadas": {
            "type": "object",
            "nullable": true,
            "properties": {
              "lat": {
                "type": "number",
                "example": -34.1702
              },
              "lng": {
                "type": "number",
                "example": -70.7408
              }
            }
          }
        }
      },
      "Lectura": {
        "type": "object",
        "description": "Una fila agregada por hora o por día (hora del campo). `inicio` es el instante real de inicio del período. Por día, `hora` es null.",
        "properties": {
          "fecha": {
            "type": "string",
            "example": "2026-10-14",
            "description": "Día del campo (AAAA-MM-DD)"
          },
          "hora": {
            "type": "string",
            "nullable": true,
            "example": "13:00",
            "description": "Hora del campo (HH:00); null por día"
          },
          "inicio": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "example": "2026-10-14T16:00:00.000Z"
          },
          "tipoSensor": {
            "type": "string",
            "example": "Soil Moisture"
          },
          "profundidad": {
            "type": "number",
            "nullable": true,
            "example": 40
          },
          "unidadProfundidad": {
            "type": "string",
            "nullable": true,
            "example": "cm"
          },
          "unidad": {
            "type": "string",
            "nullable": true,
            "example": "%"
          },
          "promedio": {
            "type": "number",
            "nullable": true
          },
          "minimo": {
            "type": "number",
            "nullable": true
          },
          "maximo": {
            "type": "number",
            "nullable": true
          },
          "ultimo": {
            "type": "number",
            "nullable": true
          },
          "suma": {
            "type": "number",
            "nullable": true,
            "description": "Útil en lluvia y riego (acumulados)"
          },
          "cantidad": {
            "type": "number",
            "nullable": true,
            "description": "Lecturas crudas agregadas"
          }
        }
      },
      "Riego": {
        "type": "object",
        "properties": {
          "sectorId": {
            "type": "string",
            "pattern": "^[a-f0-9]{24}$",
            "example": "66f1c0a2b3d4e5f6a7b8c9d0",
            "nullable": true,
            "description": "null si el sector fue borrado"
          },
          "sectorNombre": {
            "type": "string",
            "nullable": true
          },
          "inicio": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "fin": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "estado": {
            "type": "string",
            "nullable": true,
            "example": "Executed OK"
          },
          "tipo": {
            "type": "string",
            "nullable": true
          },
          "volumen": {
            "type": "object",
            "nullable": true,
            "properties": {
              "valor": {
                "type": "number",
                "nullable": true
              },
              "unidad": {
                "type": "string",
                "nullable": true,
                "example": "m3"
              }
            }
          },
          "precipitacion": {
            "type": "object",
            "nullable": true,
            "properties": {
              "valor": {
                "type": "number",
                "nullable": true
              },
              "unidad": {
                "type": "string",
                "nullable": true,
                "example": "m3"
              }
            },
            "description": "mm"
          },
          "manual": {
            "type": "boolean",
            "description": "true si fue un riego manual (no programado)"
          }
        }
      }
    },
    "headers": {
      "X-RateLimit-Limit": {
        "description": "Peticiones permitidas por minuto (60 por defecto)",
        "schema": {
          "type": "integer"
        }
      },
      "X-RateLimit-Remaining": {
        "description": "Peticiones que quedan en el minuto en curso",
        "schema": {
          "type": "integer"
        }
      },
      "X-RateLimit-Limit-Day": {
        "description": "Peticiones permitidas por día UTC (10000 por defecto)",
        "schema": {
          "type": "integer"
        }
      },
      "X-RateLimit-Remaining-Day": {
        "description": "Peticiones que quedan en el día",
        "schema": {
          "type": "integer"
        }
      },
      "Retry-After": {
        "description": "Solo en 429: segundos hasta poder reintentar",
        "schema": {
          "type": "integer"
        }
      }
    },
    "parameters": {
      "campoId": {
        "in": "path",
        "name": "campoId",
        "required": true,
        "schema": {
          "type": "string",
          "pattern": "^[a-f0-9]{24}$",
          "example": "66f1c0a2b3d4e5f6a7b8c9d0"
        }
      },
      "desde": {
        "in": "query",
        "name": "desde",
        "required": true,
        "description": "Inicio del rango (ISO 8601, instante real; con zona o en UTC)",
        "schema": {
          "type": "string",
          "format": "date-time",
          "example": "2026-10-01T00:00:00-03:00"
        }
      },
      "hasta": {
        "in": "query",
        "name": "hasta",
        "required": true,
        "description": "Fin del rango (exclusivo). A lo más 31 días desde `desde` (7 con granularidad=hora)",
        "schema": {
          "type": "string",
          "format": "date-time",
          "example": "2026-10-15T00:00:00-03:00"
        }
      },
      "limite": {
        "in": "query",
        "name": "limite",
        "description": "Filas por página (500 por defecto, máximo 1000)",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 1000
        }
      },
      "cursor": {
        "in": "query",
        "name": "cursor",
        "description": "`paginacion.siguienteCursor` de la página anterior, con la misma consulta",
        "schema": {
          "type": "string"
        }
      },
      "granularidad": {
        "in": "query",
        "name": "granularidad",
        "description": "Agregación por hora o por día del campo",
        "schema": {
          "type": "string",
          "enum": [
            "hora",
            "dia"
          ],
          "default": "dia"
        }
      },
      "tipoClima": {
        "in": "query",
        "name": "tipoSensor",
        "description": "Sin indicar, todas las variables de clima.",
        "schema": {
          "type": "string",
          "enum": [
            "Temperature",
            "Humidity",
            "Rain",
            "Solar Radiation",
            "Wind Velocity",
            "Wind Speed",
            "Wind Direction",
            "Wind Gust",
            "Atmospheric Pressure",
            "UV Index",
            "ET Davis"
          ]
        }
      }
    },
    "responses": {
      "Cuenta": {
        "description": "Cuenta de la llave",
        "headers": {
          "X-RateLimit-Limit": {
            "$ref": "#/components/headers/X-RateLimit-Limit"
          },
          "X-RateLimit-Remaining": {
            "$ref": "#/components/headers/X-RateLimit-Remaining"
          },
          "X-RateLimit-Limit-Day": {
            "$ref": "#/components/headers/X-RateLimit-Limit-Day"
          },
          "X-RateLimit-Remaining-Day": {
            "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "required": [
                "data"
              ],
              "properties": {
                "data": {
                  "$ref": "#/components/schemas/Cuenta"
                }
              }
            }
          }
        }
      },
      "Campo": {
        "description": "Campo",
        "headers": {
          "X-RateLimit-Limit": {
            "$ref": "#/components/headers/X-RateLimit-Limit"
          },
          "X-RateLimit-Remaining": {
            "$ref": "#/components/headers/X-RateLimit-Remaining"
          },
          "X-RateLimit-Limit-Day": {
            "$ref": "#/components/headers/X-RateLimit-Limit-Day"
          },
          "X-RateLimit-Remaining-Day": {
            "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "required": [
                "data"
              ],
              "properties": {
                "data": {
                  "$ref": "#/components/schemas/Campo"
                }
              }
            }
          }
        }
      },
      "Campos": {
        "description": "Lista de campos",
        "headers": {
          "X-RateLimit-Limit": {
            "$ref": "#/components/headers/X-RateLimit-Limit"
          },
          "X-RateLimit-Remaining": {
            "$ref": "#/components/headers/X-RateLimit-Remaining"
          },
          "X-RateLimit-Limit-Day": {
            "$ref": "#/components/headers/X-RateLimit-Limit-Day"
          },
          "X-RateLimit-Remaining-Day": {
            "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "required": [
                "data"
              ],
              "properties": {
                "data": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Campo"
                  }
                }
              }
            }
          }
        }
      },
      "Sectores": {
        "description": "Lista de sectores",
        "headers": {
          "X-RateLimit-Limit": {
            "$ref": "#/components/headers/X-RateLimit-Limit"
          },
          "X-RateLimit-Remaining": {
            "$ref": "#/components/headers/X-RateLimit-Remaining"
          },
          "X-RateLimit-Limit-Day": {
            "$ref": "#/components/headers/X-RateLimit-Limit-Day"
          },
          "X-RateLimit-Remaining-Day": {
            "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "required": [
                "data"
              ],
              "properties": {
                "data": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Sector"
                  }
                }
              }
            }
          }
        }
      },
      "Equipos": {
        "description": "Lista de equipos",
        "headers": {
          "X-RateLimit-Limit": {
            "$ref": "#/components/headers/X-RateLimit-Limit"
          },
          "X-RateLimit-Remaining": {
            "$ref": "#/components/headers/X-RateLimit-Remaining"
          },
          "X-RateLimit-Limit-Day": {
            "$ref": "#/components/headers/X-RateLimit-Limit-Day"
          },
          "X-RateLimit-Remaining-Day": {
            "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "required": [
                "data"
              ],
              "properties": {
                "data": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Equipo"
                  }
                }
              }
            }
          }
        }
      },
      "Estaciones": {
        "description": "Lista de estaciones de clima",
        "headers": {
          "X-RateLimit-Limit": {
            "$ref": "#/components/headers/X-RateLimit-Limit"
          },
          "X-RateLimit-Remaining": {
            "$ref": "#/components/headers/X-RateLimit-Remaining"
          },
          "X-RateLimit-Limit-Day": {
            "$ref": "#/components/headers/X-RateLimit-Limit-Day"
          },
          "X-RateLimit-Remaining-Day": {
            "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "required": [
                "data"
              ],
              "properties": {
                "data": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Equipo"
                  }
                }
              }
            }
          }
        }
      },
      "Riegos": {
        "description": "Página de riegos",
        "headers": {
          "X-RateLimit-Limit": {
            "$ref": "#/components/headers/X-RateLimit-Limit"
          },
          "X-RateLimit-Remaining": {
            "$ref": "#/components/headers/X-RateLimit-Remaining"
          },
          "X-RateLimit-Limit-Day": {
            "$ref": "#/components/headers/X-RateLimit-Limit-Day"
          },
          "X-RateLimit-Remaining-Day": {
            "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "required": [
                "data",
                "paginacion"
              ],
              "properties": {
                "data": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Riego"
                  }
                },
                "paginacion": {
                  "$ref": "#/components/schemas/Paginacion"
                }
              }
            }
          }
        }
      },
      "Lecturas": {
        "description": "Página de lecturas agregadas",
        "headers": {
          "X-RateLimit-Limit": {
            "$ref": "#/components/headers/X-RateLimit-Limit"
          },
          "X-RateLimit-Remaining": {
            "$ref": "#/components/headers/X-RateLimit-Remaining"
          },
          "X-RateLimit-Limit-Day": {
            "$ref": "#/components/headers/X-RateLimit-Limit-Day"
          },
          "X-RateLimit-Remaining-Day": {
            "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "required": [
                "data",
                "paginacion"
              ],
              "properties": {
                "data": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Lectura"
                  }
                },
                "paginacion": {
                  "$ref": "#/components/schemas/Paginacion"
                }
              }
            }
          }
        }
      },
      "Clima": {
        "description": "Página de lecturas de clima agregadas",
        "headers": {
          "X-RateLimit-Limit": {
            "$ref": "#/components/headers/X-RateLimit-Limit"
          },
          "X-RateLimit-Remaining": {
            "$ref": "#/components/headers/X-RateLimit-Remaining"
          },
          "X-RateLimit-Limit-Day": {
            "$ref": "#/components/headers/X-RateLimit-Limit-Day"
          },
          "X-RateLimit-Remaining-Day": {
            "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "required": [
                "data",
                "paginacion"
              ],
              "properties": {
                "data": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Lectura"
                  }
                },
                "paginacion": {
                  "$ref": "#/components/schemas/Paginacion"
                }
              }
            }
          }
        }
      },
      "NoAutenticado": {
        "description": "Llave inválida, revocada, vencida o ausente; o su dueño perdió el acceso",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "codigo": "no_autenticado",
                "mensaje": "Llave de API inválida o ausente."
              }
            }
          }
        }
      },
      "NoEncontrado": {
        "description": "No existe o no es de la cuenta de la llave (se responde igual en ambos casos)",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "codigo": "no_encontrado",
                "mensaje": "Recurso no encontrado."
              }
            }
          }
        }
      },
      "Parametros": {
        "description": "Parámetros inválidos (rango, cursor, parámetro desconocido, etc.)",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "codigo": "parametros_invalidos",
                "mensaje": "El rango no puede superar 31 días"
              }
            }
          }
        }
      },
      "Demasiadas": {
        "description": "Límite de peticiones superado; `Retry-After` dice cuántos segundos esperar",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "codigo": "demasiadas_peticiones",
                "mensaje": "Se superó el límite de peticiones."
              }
            }
          }
        },
        "headers": {
          "Retry-After": {
            "$ref": "#/components/headers/Retry-After"
          }
        }
      },
      "NoDisponible": {
        "description": "La API no está disponible (mantenimiento)",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "codigo": "no_disponible",
                "mensaje": "La API no está disponible."
              }
            }
          }
        }
      }
    }
  },
  "security": [
    {
      "apiKey": []
    },
    {
      "bearer": []
    }
  ],
  "paths": {
    "/cuenta": {
      "get": {
        "tags": [
          "Cuenta"
        ],
        "summary": "Cuenta de la llave y datos de la llave (sin el secreto).",
        "description": "Sirve para probar la llave: devuelve la cuenta, cuántos campos puede leer y el prefijo de la llave con que se autenticó.",
        "responses": {
          "200": {
            "$ref": "#/components/responses/Cuenta"
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "429": {
            "$ref": "#/components/responses/Demasiadas"
          }
        }
      }
    },
    "/campos": {
      "get": {
        "tags": [
          "Campos"
        ],
        "summary": "Campos que la llave puede leer, con centro y polígono.",
        "description": "Ordenados por nombre. Con una llave generada en Mi cuenta › API son exactamente los campos que ese usuario ve en la plataforma.",
        "responses": {
          "200": {
            "$ref": "#/components/responses/Campos"
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "429": {
            "$ref": "#/components/responses/Demasiadas"
          }
        }
      }
    },
    "/campos/{campoId}": {
      "get": {
        "tags": [
          "Campos"
        ],
        "summary": "Un campo. Un campo ajeno responde igual que uno inexistente (404).",
        "parameters": [
          {
            "$ref": "#/components/parameters/campoId"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/Campo"
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "404": {
            "$ref": "#/components/responses/NoEncontrado"
          },
          "429": {
            "$ref": "#/components/responses/Demasiadas"
          }
        }
      }
    },
    "/campos/{campoId}/sectores": {
      "get": {
        "tags": [
          "Campos"
        ],
        "summary": "Sectores vigentes del campo, con su polígono y configuración de riego.",
        "parameters": [
          {
            "$ref": "#/components/parameters/campoId"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/Sectores"
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "404": {
            "$ref": "#/components/responses/NoEncontrado"
          },
          "429": {
            "$ref": "#/components/responses/Demasiadas"
          }
        }
      }
    },
    "/campos/{campoId}/equipos": {
      "get": {
        "tags": [
          "Campos"
        ],
        "summary": "Equipos (sondas, sensores y estaciones) vigentes del campo.",
        "parameters": [
          {
            "$ref": "#/components/parameters/campoId"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/Equipos"
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "404": {
            "$ref": "#/components/responses/NoEncontrado"
          },
          "429": {
            "$ref": "#/components/responses/Demasiadas"
          }
        }
      }
    },
    "/campos/{campoId}/estaciones": {
      "get": {
        "tags": [
          "Clima"
        ],
        "summary": "Estaciones de clima vigentes del campo.",
        "parameters": [
          {
            "$ref": "#/components/parameters/campoId"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/Estaciones"
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "404": {
            "$ref": "#/components/responses/NoEncontrado"
          },
          "429": {
            "$ref": "#/components/responses/Demasiadas"
          }
        }
      }
    },
    "/campos/{campoId}/riegos": {
      "get": {
        "tags": [
          "Riego"
        ],
        "summary": "Riegos registrados del campo (programados y manuales), solo lo ya sincronizado; las últimas horas pueden no estar aún. Solo lectura.",
        "parameters": [
          {
            "$ref": "#/components/parameters/campoId"
          },
          {
            "$ref": "#/components/parameters/desde"
          },
          {
            "$ref": "#/components/parameters/hasta"
          },
          {
            "in": "query",
            "name": "sectorId",
            "description": "Solo los riegos de ese sector (debe ser del campo)",
            "schema": {
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/limite"
          },
          {
            "$ref": "#/components/parameters/cursor"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/Riegos"
          },
          "400": {
            "$ref": "#/components/responses/Parametros"
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "404": {
            "$ref": "#/components/responses/NoEncontrado"
          },
          "429": {
            "$ref": "#/components/responses/Demasiadas"
          }
        }
      }
    },
    "/lecturas": {
      "get": {
        "tags": [
          "Lecturas"
        ],
        "summary": "Lecturas agregadas por hora o por día de un sector o de un equipo (promedio, mínimo, máximo, último, suma y cantidad por tipo y profundidad).",
        "description": "Las filas vienen por día u hora **del campo** (`fecha`, `hora`) y con `inicio` como instante real. Un `hasta` futuro se recorta al presente. No hay lecturas crudas.",
        "parameters": [
          {
            "in": "query",
            "name": "sectorId",
            "description": "Id del sector (se indica sectorId o equipoId, no ambos)",
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "equipoId",
            "description": "Id del equipo (sonda, sensor o estación)",
            "schema": {
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/desde"
          },
          {
            "$ref": "#/components/parameters/hasta"
          },
          {
            "in": "query",
            "name": "tipoSensor",
            "required": true,
            "description": "Tipo de sensor tal como lo entrega `tipoSensor` en /campos/{campoId}/equipos, p. ej. `Soil Moisture`, `Temperature`, `Humidity`, `Rain`.",
            "schema": {
              "type": "string",
              "example": "Soil Moisture"
            }
          },
          {
            "$ref": "#/components/parameters/granularidad"
          },
          {
            "$ref": "#/components/parameters/limite"
          },
          {
            "$ref": "#/components/parameters/cursor"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/Lecturas"
          },
          "400": {
            "$ref": "#/components/responses/Parametros"
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "404": {
            "$ref": "#/components/responses/NoEncontrado"
          },
          "429": {
            "$ref": "#/components/responses/Demasiadas"
          }
        }
      }
    },
    "/estaciones/{estacionId}/clima": {
      "get": {
        "tags": [
          "Clima"
        ],
        "summary": "Clima agregado por hora o por día de una estación del cliente.",
        "description": "Todas las variables de la estación en una sola página (o una, con `tipoSensor`). Mismo formato de fila que /lecturas.",
        "parameters": [
          {
            "in": "path",
            "name": "estacionId",
            "required": true,
            "description": "Id de una estación de /campos/{campoId}/estaciones",
            "schema": {
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/desde"
          },
          {
            "$ref": "#/components/parameters/hasta"
          },
          {
            "$ref": "#/components/parameters/tipoClima"
          },
          {
            "$ref": "#/components/parameters/granularidad"
          },
          {
            "$ref": "#/components/parameters/limite"
          },
          {
            "$ref": "#/components/parameters/cursor"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/Clima"
          },
          "400": {
            "$ref": "#/components/responses/Parametros"
          },
          "401": {
            "$ref": "#/components/responses/NoAutenticado"
          },
          "404": {
            "$ref": "#/components/responses/NoEncontrado"
          },
          "429": {
            "$ref": "#/components/responses/Demasiadas"
          }
        }
      }
    }
  }
}
