{
  "openapi": "3.1.0",
  "info": {
    "title": "HERALD Feed — Agent-Narrow Catalog API (Lite)",
    "description": "Catalog of vehicles, machinery, equipment and other auction assets in Peru (VMC Subastas). Catalog responses use display-ready Lite fields. Render them verbatim and use canonical_url. DonJusto market valuations are available for supported vehicle makes, models and years; coverage is not guaranteed for every asset.",
    "version": "1.1.0",
    "contact": {
      "name": "HERALD Feed API Access",
      "email": "pinzon@subastop.com",
      "url": "https://www.vmcsubastas.com"
    }
  },
  "servers": [
    {
      "url": "https://feed.vmcsubastas.com",
      "description": "Production"
    }
  ],
  "paths": {
    "/herald/v1/agent/lots": {
      "get": {
        "operationId": "getVehicleCatalog",
        "summary": "Browse the vehicle auction catalog",
        "description": "Returns the current vehicle catalog filtered by query params. Default: 'activa' state (currently bookable — negotiable lots + live lots scheduled for a future date). Each item is an AgentSnapshotLite with display-ready strings — render verbatim, never construct alternatives.",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "activa",
                "terminada"
              ]
            },
            "description": "Filter by auction status. Binary lifecycle: 'activa' (currently bookable) or 'terminada' (closed). Default: 'activa'."
          },
          {
            "name": "make",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Filter by vehicle make (case-insensitive). Examples: Toyota, Hyundai, Kia, Nissan, Chevrolet."
          },
          {
            "name": "model",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Filter by vehicle model (exact match, case-insensitive, whitespace-tolerant). Example: 'Hilux', 'Tucson', 'HR-V'."
          },
          {
            "name": "year",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "description": "Filter by exact model year. When present, year_from/year_to are ignored."
          },
          {
            "name": "year_from",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "description": "Inclusive lower bound for model year. Ignored if `year` (exact) is also provided."
          },
          {
            "name": "year_to",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "description": "Inclusive upper bound for model year. Ignored if `year` (exact) is also provided."
          },
          {
            "name": "category",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "seminuevo",
                "salvamento",
                "recuperado",
                "chatarra",
                "repuestos",
                "maquinaria"
              ]
            },
            "description": "Filter by vehicle category. seminuevo=pre-owned, salvamento=salvage, recuperado=recovered, chatarra=scrap, repuestos=parts, maquinaria=machinery."
          },
          {
            "name": "seller",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Filter by seller name (partial match, case-insensitive, accent-insensitive)."
          },
          {
            "name": "min_price",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Minimum base price in USD."
          },
          {
            "name": "max_price",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Maximum base price in USD."
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "publication_date",
                "base_price",
                "auction_date"
              ],
              "default": "publication_date"
            },
            "description": "Sort field."
          },
          {
            "name": "order",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ],
              "default": "desc"
            },
            "description": "Sort order."
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 1
            },
            "description": "Page number (1-indexed)."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "maximum": 100
            },
            "description": "Results per page (max 100)."
          }
        ],
        "responses": {
          "200": {
            "description": "Vehicle catalog results",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "herald_version",
                    "total",
                    "page",
                    "limit",
                    "data"
                  ],
                  "properties": {
                    "herald_version": {
                      "type": "string"
                    },
                    "total": {
                      "type": "integer",
                      "description": "Total lots matching the filters (before pagination)."
                    },
                    "page": {
                      "type": "integer"
                    },
                    "limit": {
                      "type": "integer"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AgentSnapshotLite"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/herald/v1/agent/lots/{lot_id}": {
      "get": {
        "operationId": "getVehicleLot",
        "summary": "Get details for a specific vehicle lot",
        "description": "Returns the AgentSnapshotLite for a single vehicle lot by ID. Use this when the user asks about a specific lot ('Oferta 62057') or in any follow-up question about a previously-shown lot.",
        "parameters": [
          {
            "name": "lot_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Lot identifier."
          }
        ],
        "responses": {
          "200": {
            "description": "Single lot detail",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AgentSnapshotLite"
                }
              }
            }
          },
          "404": {
            "description": "Lot not found"
          }
        }
      }
    },
    "/herald/v1/agent/new": {
      "get": {
        "operationId": "getRecentlyPublished",
        "summary": "Get recently published vehicles",
        "description": "Returns vehicles published within the lookback window. Use this to answer 'what's new', 'latest listings', 'what was published this week'.",
        "parameters": [
          {
            "name": "hours",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 24,
              "maximum": 168
            },
            "description": "Lookback window in hours (max 168 = 7 days)."
          },
          {
            "name": "make",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Filter by vehicle make."
          },
          {
            "name": "category",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Filter by vehicle category."
          }
        ],
        "responses": {
          "200": {
            "description": "Recently published vehicles",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "herald_version",
                    "hours",
                    "total",
                    "data"
                  ],
                  "properties": {
                    "herald_version": {
                      "type": "string"
                    },
                    "hours": {
                      "type": "integer"
                    },
                    "total": {
                      "type": "integer"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AgentSnapshotLite"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/herald/v1/health": {
      "get": {
        "operationId": "getServiceHealth",
        "summary": "Check feed health and data freshness",
        "description": "Returns service status, total lot count, active lot count, and data freshness. No authentication required.",
        "responses": {
          "200": {
            "description": "Service health",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "enum": [
                        "ok",
                        "degraded"
                      ]
                    },
                    "herald_version": {
                      "type": "string"
                    },
                    "total_lots": {
                      "type": "integer"
                    },
                    "active_lots": {
                      "type": "integer"
                    },
                    "last_ingest_at": {
                      "type": "string",
                      "format": "date-time",
                      "nullable": true
                    },
                    "last_catalog_sync_at": {
                      "type": "string",
                      "format": "date-time",
                      "nullable": true
                    },
                    "avg_freshness_seconds": {
                      "type": "number"
                    }
                  }
                }
              }
            }
          }
        },
        "security": []
      }
    },
    "/herald/v1/market/{make}": {
      "get": {
        "operationId": "getMarketMake",
        "summary": "List models and years available for a make",
        "description": "Returns models and years from the HERALD catalog. Use to narrow the query before a valuation.",
        "parameters": [
          {
            "name": "make",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Valuation or catalog coverage result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MarketMakeDetail"
                }
              }
            }
          },
          "404": {
            "description": "No data for the requested make/model/year"
          }
        }
      }
    },
    "/herald/v1/market/{make}/{model}": {
      "get": {
        "operationId": "getMarketModelValuation",
        "summary": "Get DonJusto valuations across available years",
        "description": "Returns DonJusto valuations for available model years. Use when make and model are known but year is missing.",
        "parameters": [
          {
            "name": "make",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "model",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Valuation or catalog coverage result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MarketModelValuation"
                }
              }
            }
          },
          "404": {
            "description": "No data for the requested make/model/year"
          }
        }
      }
    },
    "/herald/v1/market/{make}/{model}/{year}": {
      "get": {
        "operationId": "getMarketYearValuation",
        "summary": "Get DonJusto valuation for a make, model and year",
        "description": "Returns a DonJusto estimate. May fall back up to three prior years; disclose status approximate and matched_year. Estimates do not account for the specific vehicle condition, mileage, trim or equipment.",
        "parameters": [
          {
            "name": "make",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "model",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "year",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Valuation or catalog coverage result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MarketYearValuation"
                }
              }
            }
          },
          "404": {
            "description": "No data for the requested make/model/year"
          }
        }
      }
    },
    "/herald/v1/resources": {
      "get": {
        "operationId": "searchResources",
        "summary": "Buscar artículos publicados de SubasBlog y enlaces de evaluación o catálogo",
        "description": "Recursos editoriales recientes del RSS público, no inventario ni términos comerciales garantizados. Búsqueda por palabras en título, resumen y temas. No cubre todo el archivo. Actualización en la primera consulta de cada día de lunes a viernes, hora de Lima. Conserva la última copia si falla el RSS; revisar fetched_at y stale.",
        "security": [],
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "schema": {
              "type": "string",
              "maxLength": 160
            }
          },
          {
            "name": "audience",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "seller",
                "buyer",
                "general"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 20,
              "default": 5
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Artículos publicados con fuente, fecha, resumen y CTA; fetched_at indica última lectura del RSS.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "source_url": {
                      "type": "string"
                    },
                    "coverage": {
                      "type": "string"
                    },
                    "fetched_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "total": {
                      "type": "integer"
                    },
                    "resources": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "title": {
                            "type": "string"
                          },
                          "summary": {
                            "type": "string"
                          },
                          "url": {
                            "type": "string",
                            "format": "uri"
                          },
                          "published_at": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "topics": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "audience": {
                            "type": "string"
                          },
                          "source": {
                            "type": "string"
                          },
                          "cta": {
                            "type": "object",
                            "properties": {
                              "label": {
                                "type": "string"
                              },
                              "url": {
                                "type": "string",
                                "format": "uri"
                              }
                            }
                          }
                        }
                      }
                    },
                    "stale": {
                      "type": "boolean",
                      "description": "La última copia no se pudo actualizar en el día laborable actual."
                    },
                    "refresh_schedule": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Consulta inválida"
          },
          "503": {
            "description": "RSS no disponible; no se entregan resultados obsoletos"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "AgentSnapshotLite": {
        "type": "object",
        "description": "Narrow display-ready shape for LLM-driven agents. Every string field is render-ready: trimmed, formatted, and authoritative. The consumer (agent) concatenates verbatim — it does NOT compose, infer, or construct any of these values.",
        "required": [
          "lot_id",
          "lot_code",
          "canonical_url",
          "vehicle_display",
          "price_display",
          "status_label",
          "seller_name"
        ],
        "properties": {
          "lot_id": {
            "type": "integer",
            "description": "Numeric lot identifier. Use this when calling getVehicleLot. Do not display the bare number — display lot_code instead.",
            "example": 62057
          },
          "lot_code": {
            "type": "string",
            "description": "Pre-formatted human label, always 'Oferta {lot_id}'. Render verbatim. Never substitute alternatives like 'LOT-X', 'ID 62057', or 'Listing #62057'.",
            "example": "Oferta 62057"
          },
          "canonical_url": {
            "type": "string",
            "format": "uri",
            "description": "Canonical public URL for this listing. Always 'https://www.vmcsubastas.com/oferta/{lot_id}'. Use VERBATIM as a markdown link target — never construct, never substitute '/index.html' or '/vehicular.html', never derive from make/model.",
            "example": "https://www.vmcsubastas.com/oferta/62057"
          },
          "vehicle_display": {
            "type": "string",
            "description": "Pre-formatted 'Make Model Year' with all whitespace cleaned. Render verbatim.",
            "example": "Chevrolet Onix 2022"
          },
          "price_display": {
            "type": "string",
            "description": "Pre-formatted base price 'USD with comma thousands, no decimals, no suffix'. Render verbatim. Never alter, round, or convert to other currencies.",
            "example": "$6,999"
          },
          "status_label": {
            "type": "string",
            "enum": [
              "En vivo",
              "Próxima",
              "Negociable"
            ],
            "description": "Bookable-state label derived server-side from auction type and date. Render verbatim — never derive 'En vivo' vs 'Próxima' on the client.",
            "example": "Próxima"
          },
          "seller_name": {
            "type": "string",
            "description": "Seller's commercial name, already trimmed. Render verbatim. 'VMC Subastas' is the platform — it is NEVER the seller. Render the value as received.",
            "example": "Santander Consumer"
          },
          "auction_date_display": {
            "type": "string",
            "nullable": true,
            "description": "Pre-formatted auction date 'DD mmm YYYY HH:mm' in Peru timezone (UTC-5). Null when there is no scheduled auction. When non-null, render verbatim.",
            "example": "27 may 2026 16:55"
          },
          "market_estimate_display": {
            "type": "string",
            "nullable": true,
            "description": "Pre-formatted market estimate envelope 'USD reference (Rango: USD low – USD high)' or null when no market valuation is available. When non-null, render verbatim as the third display line. When null, omit the line entirely. Never quote raw numbers, never invent a market estimate.",
            "example": "$12,950 (Rango: $12,040 – $14,250)"
          }
        }
      },
      "MarketMakeDetail": {
        "type": "object",
        "description": "Models and model-years available for a make, derived from the HERALD lot catalog.",
        "required": [
          "make",
          "total_models",
          "lot_count",
          "models"
        ],
        "properties": {
          "make": {
            "type": "string"
          },
          "total_models": {
            "type": "integer"
          },
          "lot_count": {
            "type": "integer"
          },
          "models": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "model": {
                  "type": "string"
                },
                "lot_count": {
                  "type": "integer"
                },
                "years_available": {
                  "type": "array",
                  "items": {
                    "type": "integer"
                  }
                }
              }
            }
          }
        }
      },
      "MarketModelValuation": {
        "type": "object",
        "description": "DonJusto valuation fields used by MAX, by model year.",
        "required": [
          "make",
          "model",
          "valuations"
        ],
        "properties": {
          "make": {
            "type": "string"
          },
          "model": {
            "type": "string"
          },
          "valuations": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "year",
                "value",
                "currency"
              ],
              "properties": {
                "year": {
                  "type": "integer"
                },
                "value": {
                  "type": "object",
                  "required": [
                    "conservative",
                    "market",
                    "optimistic"
                  ],
                  "properties": {
                    "conservative": {
                      "type": "number"
                    },
                    "market": {
                      "type": "number"
                    },
                    "optimistic": {
                      "type": "number"
                    }
                  }
                },
                "currency": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "MarketYearValuation": {
        "type": "object",
        "description": "DonJusto valuation fields used by MAX.",
        "required": [
          "make",
          "model",
          "year",
          "value",
          "currency"
        ],
        "properties": {
          "make": {
            "type": "string"
          },
          "model": {
            "type": "string"
          },
          "year": {
            "type": "integer"
          },
          "status": {
            "type": "string",
            "enum": [
              "ok",
              "approximate"
            ]
          },
          "matched_year": {
            "type": "integer",
            "description": "Year actually valued when status is approximate."
          },
          "value": {
            "type": "object",
            "required": [
              "conservative",
              "market",
              "optimistic"
            ],
            "properties": {
              "conservative": {
                "type": "number"
              },
              "market": {
                "type": "number"
              },
              "optimistic": {
                "type": "number"
              }
            }
          },
          "currency": {
            "type": "string"
          }
        }
      }
    },
    "securitySchemes": {
      "HeraldBearer": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "Preferred authentication scheme. Obtain a provisioned HERALD Bearer token and honor its returned expires_in value."
      },
      "HeraldKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Herald-Key",
        "description": "DEPRECATED — transition-only fallback for existing integrations. Do not use for new integrations."
      }
    }
  },
  "security": [
    {
      "HeraldBearer": []
    },
    {
      "HeraldKey": []
    }
  ]
}
