{
  "openapi": "3.1.0",
  "info": {
    "title": "Pricelists.org Agent Commerce API",
    "summary": "Price comparison data and agent-driven purchasing across millions of offers.",
    "description": "Machine-readable price comparison API built for AI agents.\n\nThe catalogue tracks product offers from many merchants, normalises every price to USD internally, and records a price history whenever a price or stock level changes. Agents can search offers, request a binding quote, execute a purchase (or fall back to a checkout URL when a merchant does not support programmatic execution), and submit their own pricelists for moderation.\n\nGetting started takes one call: POST /api/agent/v1/register with a name returns a working API key immediately, with no approval step.\n\nHuman-readable documentation: https://pricelists.org/en/agent-docs",
    "version": "1.0.0",
    "license": {
      "name": "MIT",
      "identifier": "MIT"
    },
    "contact": {
      "name": "Pricelists.org",
      "url": "https://pricelists.org/en/agent-docs"
    }
  },
  "servers": [
    {
      "url": "https://pricelists.org",
      "description": "Production"
    }
  ],
  "tags": [
    { "name": "Discovery", "description": "Finding offers. No authentication required." },
    { "name": "Authentication", "description": "Obtaining an API key." },
    { "name": "Purchasing", "description": "Quote, execute and track orders." },
    { "name": "Submissions", "description": "Contributing pricelist data." }
  ],
  "security": [{ "bearerAuth": [] }],
  "paths": {
    "/api/agent/v1/register": {
      "post": {
        "tags": ["Authentication"],
        "summary": "Create an API key",
        "description": "Self-service registration. Returns a plaintext key exactly once — it is stored only as a SHA-256 hash and cannot be recovered afterwards. Rate limited to 5 requests per minute per IP.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["name"],
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 255,
                    "description": "Identifies the agent in rate-limit and audit records.",
                    "examples": ["shopping-assistant"]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Key created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "apiKey": {
                      "type": "string",
                      "description": "Send as `Authorization: Bearer <apiKey>`. Shown only in this response.",
                      "examples": ["plk_5f3a9c1e2b7d4a8f6c0e1d2b"]
                    },
                    "name": { "type": "string" },
                    "rateLimitPerMinute": { "type": "integer", "examples": [60] }
                  }
                }
              }
            }
          },
          "422": { "$ref": "#/components/responses/ValidationError" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/api/agent/v1/search": {
      "get": {
        "tags": ["Discovery"],
        "summary": "Search usage hint",
        "description": "Returns a pointer to the POST endpoint. Search itself requires POST because the filter payload is structured.",
        "security": [],
        "responses": {
          "200": {
            "description": "Hint payload.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": { "type": "string" },
                    "docs": { "type": "string", "format": "uri" },
                    "method": { "type": "string", "const": "POST" }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": ["Discovery"],
        "summary": "Search offers",
        "description": "Finds offers by product identifier or free-text query.\n\nIdentifier lookups (GTIN/EAN/MPN) are exact matches and are tried first; a free-text `query` falls back to the search index. Results are returned under one entry per requested ranking.\n\nRanking modes: `cheapest` orders purely by price; `best` blends merchant credibility, price and delivery speed using `bestWeights` (defaults favour credibility).\n\nNo authentication required. Rate limited to 30 requests per minute per IP.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/SearchRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Ranked offers.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/SearchResponse" }
              }
            }
          },
          "422": { "$ref": "#/components/responses/ValidationError" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/api/agent/v1/products/{id}": {
      "get": {
        "tags": ["Discovery"],
        "summary": "Get a product with all its offers",
        "description": "Linkable, cacheable view of a single product. Unlike POST /search this is a plain URL, so it can be quoted in an answer, fetched by a generic GET-only tool, and cached by a CDN.\n\nResponses carry an `ETag`; send it back as `If-None-Match` to get a 304 without spending rate-limit budget.\n\nNo authentication required.",
        "security": [],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Product id, with or without the `prod_` prefix.",
            "schema": { "type": "string" },
            "examples": { "prefixed": { "value": "prod_987" }, "bare": { "value": "987" } }
          },
          {
            "name": "currency",
            "in": "query",
            "schema": { "type": "string", "minLength": 3, "maxLength": 3, "default": "USD" }
          },
          {
            "name": "locale",
            "in": "query",
            "schema": { "type": "string", "maxLength": 10 }
          }
        ],
        "responses": {
          "200": {
            "description": "Product with offers.",
            "headers": {
              "ETag": { "schema": { "type": "string" } },
              "Cache-Control": { "schema": { "type": "string" }, "description": "public, max-age=300" }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "product": {
                      "type": "object",
                      "properties": {
                        "id": { "type": "string" },
                        "title": { "type": ["string", "null"] },
                        "description": { "type": ["string", "null"] },
                        "identifiers": { "type": "object" },
                        "imageUrl": { "type": ["string", "null"], "format": "uri" },
                        "url": { "type": "string", "format": "uri" }
                      }
                    },
                    "offerCount": { "type": "integer" },
                    "offers": { "type": "array", "items": { "$ref": "#/components/schemas/Offer" } },
                    "links": {
                      "type": "object",
                      "properties": {
                        "offers": { "type": "string", "format": "uri" },
                        "priceHistory": { "type": "string", "format": "uri" }
                      }
                    }
                  }
                }
              }
            }
          },
          "304": { "description": "Not modified — the supplied If-None-Match still matches." },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/api/agent/v1/products/{id}/price-history": {
      "get": {
        "tags": ["Discovery"],
        "summary": "Get aggregated price history",
        "description": "Price and stock changes are recorded every time they move, so this returns real observed history rather than a reconstruction.\n\nUse it to answer \"is this actually a good price right now\" — the one question that cannot be answered by scraping the current price from a shop.\n\nBuckets are aggregated in SQL. The window is capped at 365 days and the response at 400 points; `summary.truncated` tells you when the cap was hit. No authentication required.",
        "security": [],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string" }
          },
          {
            "name": "range",
            "in": "query",
            "description": "Window as `<number><unit>` where unit is d, w, m or y. Capped at 365 days.",
            "schema": { "type": "string", "default": "90d" },
            "examples": { "days": { "value": "90d" }, "months": { "value": "6m" } }
          },
          {
            "name": "granularity",
            "in": "query",
            "schema": { "type": "string", "enum": ["day", "week", "month"], "default": "day" }
          },
          {
            "name": "currency",
            "in": "query",
            "schema": { "type": "string", "minLength": 3, "maxLength": 3, "default": "USD" }
          }
        ],
        "responses": {
          "200": {
            "description": "Aggregated history.",
            "headers": { "ETag": { "schema": { "type": "string" } } },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "productId": { "type": "string" },
                    "currency": { "type": "string" },
                    "range": { "type": "string" },
                    "granularity": { "type": "string" },
                    "points": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "date": { "type": "string" },
                          "min": { "type": "number" },
                          "max": { "type": "number" },
                          "avg": { "type": "number" },
                          "samples": { "type": "integer" }
                        }
                      }
                    },
                    "summary": {
                      "type": "object",
                      "properties": {
                        "allTimeLow": { "type": ["number", "null"] },
                        "allTimeLowAt": { "type": ["string", "null"], "format": "date-time" },
                        "allTimeHigh": { "type": ["number", "null"] },
                        "allTimeHighAt": { "type": ["string", "null"], "format": "date-time" },
                        "pointsReturned": { "type": "integer" },
                        "truncated": { "type": "boolean" }
                      }
                    }
                  }
                }
              }
            }
          },
          "304": { "description": "Not modified." },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/api/agent/v1/merchants/{id}": {
      "get": {
        "tags": ["Discovery"],
        "summary": "Get merchant details",
        "description": "Lets an agent assess a seller before recommending a purchase: credibility, ratings, delivery window, and whether the merchant supports programmatic checkout at all. No authentication required.",
        "security": [],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Merchant id, with or without the `m_` prefix.",
            "schema": { "type": "string" }
          }
        ],
        "responses": {
          "200": {
            "description": "Merchant profile.",
            "headers": { "ETag": { "schema": { "type": "string" } } },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "merchant": {
                      "type": "object",
                      "properties": {
                        "id": { "type": "string" },
                        "name": { "type": "string" },
                        "website": { "type": ["string", "null"], "format": "uri" },
                        "country": { "type": ["string", "null"] },
                        "city": { "type": ["string", "null"] },
                        "credibilityScore": { "type": "integer" },
                        "signals": { "type": "object" },
                        "delivery": { "type": "object" },
                        "execution": { "$ref": "#/components/schemas/Execution" },
                        "url": { "type": "string", "format": "uri" }
                      }
                    },
                    "offerCount": { "type": "integer" }
                  }
                }
              }
            }
          },
          "304": { "description": "Not modified." },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/api/agent/v1/quote": {
      "post": {
        "tags": ["Purchasing"],
        "summary": "Request a quote",
        "description": "Turns an offer into a short-lived quote with a pricing snapshot. Quotes expire after 10 minutes and must be obtained before calling execute.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["offerId"],
                "properties": {
                  "offerId": { "type": "string", "examples": ["of_12345"] },
                  "currency": { "type": "string", "minLength": 3, "maxLength": 3 },
                  "shipTo": { "$ref": "#/components/schemas/ShipTo" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Quote created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "quoteId": { "type": "string" },
                    "expiresAt": { "type": "string", "format": "date-time" },
                    "offer": { "$ref": "#/components/schemas/Offer" },
                    "final": {
                      "type": "object",
                      "description": "Pricing snapshot held for the lifetime of the quote.",
                      "properties": {
                        "currency": { "type": "string" },
                        "itemPrice": { "type": "number" },
                        "total": { "type": "number" }
                      }
                    },
                    "execution": { "$ref": "#/components/schemas/Execution" }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "422": { "$ref": "#/components/responses/ValidationError" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/api/agent/v1/execute": {
      "post": {
        "tags": ["Purchasing"],
        "summary": "Execute a purchase",
        "description": "Attempts to place the order against the merchant.\n\nNot every merchant supports programmatic execution. Three outcomes are possible: the order is placed, the agent must hand off to a URL (`requires_action`), or execution is unsupported and a `checkout_url` is returned for the human to complete.\n\nRequires an `Idempotency-Key` header. Repeating a request with the same key returns the original order instead of creating a second one.",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "description": "Client-generated unique string. Guards against duplicate orders on retry.",
            "schema": { "type": "string", "maxLength": 255 }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["quoteId", "confirm"],
                "properties": {
                  "quoteId": { "type": "string" },
                  "confirm": {
                    "type": "boolean",
                    "const": true,
                    "description": "Explicit confirmation. Guards against accidental purchases."
                  },
                  "shipTo": { "$ref": "#/components/schemas/ShipTo" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Order placed, handed off, or declined with a fallback.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": { "type": "boolean" },
                    "orderId": { "type": ["string", "null"] },
                    "status": {
                      "type": "string",
                      "enum": ["placed", "pending", "requires_action", "not_supported", "failed"]
                    },
                    "merchantOrderRef": { "type": ["string", "null"] },
                    "action": {
                      "type": ["object", "null"],
                      "description": "Present when status is requires_action.",
                      "properties": { "url": { "type": "string", "format": "uri" } }
                    },
                    "fallback": {
                      "type": ["object", "null"],
                      "description": "Present when status is not_supported.",
                      "properties": { "checkout_url": { "type": "string", "format": "uri" } }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing Idempotency-Key header.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "410": {
            "description": "Quote expired. Request a new one.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
          },
          "422": { "$ref": "#/components/responses/ValidationError" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/api/agent/v1/orders/{orderId}": {
      "get": {
        "tags": ["Purchasing"],
        "summary": "Get order status",
        "description": "Returns the current state of an order created through execute. Scoped to the calling API key.",
        "parameters": [
          {
            "name": "orderId",
            "in": "path",
            "required": true,
            "schema": { "type": "string" }
          }
        ],
        "responses": {
          "200": {
            "description": "Order state.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "orderId": { "type": "string" },
                    "status": { "type": "string" },
                    "executionMode": { "type": ["string", "null"] },
                    "checkoutUrl": { "type": ["string", "null"] },
                    "receipt": { "type": ["object", "null"] },
                    "tracking": { "type": ["object", "null"] }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/api/agent/v1/submit": {
      "post": {
        "tags": ["Submissions"],
        "summary": "Submit a pricelist",
        "description": "Submits products and prices for moderation. Nothing is published until a human reviewer approves it.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["merchant", "items"],
                "properties": {
                  "merchant": {
                    "type": "object",
                    "required": ["name"],
                    "properties": {
                      "name": { "type": "string" },
                      "website": { "type": "string", "format": "uri" },
                      "country": { "type": "string", "minLength": 2, "maxLength": 2 }
                    }
                  },
                  "items": {
                    "type": "array",
                    "minItems": 1,
                    "items": {
                      "type": "object",
                      "required": ["title", "price", "currency"],
                      "properties": {
                        "title": { "type": "string" },
                        "price": { "type": "number", "exclusiveMinimum": 0 },
                        "currency": { "type": "string", "minLength": 3, "maxLength": 3 },
                        "gtin": { "type": "string" },
                        "mpn": { "type": "string" },
                        "url": { "type": "string", "format": "uri" },
                        "imageUrl": { "type": "string", "format": "uri" },
                        "inStock": { "type": "boolean" }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Submission queued for review.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "submissionId": { "type": "string" },
                    "status": { "type": "string", "examples": ["pending_review"] },
                    "itemCount": { "type": "integer" },
                    "message": { "type": "string" }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "422": { "$ref": "#/components/responses/ValidationError" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/api/agent/v1/submissions/{submissionId}": {
      "get": {
        "tags": ["Submissions"],
        "summary": "Get submission status",
        "description": "Returns review status, including per-item outcomes. An agent can only read submissions created with its own API key.",
        "parameters": [
          {
            "name": "submissionId",
            "in": "path",
            "required": true,
            "schema": { "type": "string" }
          }
        ],
        "responses": {
          "200": {
            "description": "Submission state.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "submissionId": { "type": "string" },
                    "status": {
                      "type": "string",
                      "enum": ["pending_review", "approved", "rejected", "processing", "processed"]
                    },
                    "itemCount": { "type": "integer" },
                    "items": { "type": "array", "items": { "type": "object" } }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "API key from POST /api/agent/v1/register, sent as `Authorization: Bearer plk_...`."
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "Missing or invalid API key.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "NotFound": {
        "description": "Resource does not exist or is not visible to this key.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "ValidationError": {
        "description": "Request body failed validation.",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "message": { "type": "string" },
                "errors": {
                  "type": "object",
                  "additionalProperties": { "type": "array", "items": { "type": "string" } }
                }
              }
            }
          }
        }
      },
      "RateLimited": {
        "description": "Rate limit exceeded. Back off and retry after the interval given in Retry-After.",
        "headers": {
          "Retry-After": {
            "description": "Seconds until the limit resets.",
            "schema": { "type": "integer" }
          }
        },
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "message": { "type": "string" },
          "code": { "type": "string" }
        }
      },
      "ShipTo": {
        "type": "object",
        "required": ["country"],
        "properties": {
          "country": {
            "type": "string",
            "minLength": 2,
            "maxLength": 2,
            "description": "ISO 3166-1 alpha-2.",
            "examples": ["PL"]
          },
          "postalCode": { "type": "string", "maxLength": 20 }
        }
      },
      "SearchRequest": {
        "type": "object",
        "description": "Supply `identifiers` for an exact match, or `query` for a text search. At least one is needed for useful results.",
        "properties": {
          "query": { "type": "string", "maxLength": 500, "examples": ["running shoes size 42"] },
          "identifiers": {
            "type": "object",
            "properties": {
              "gtin": { "type": "array", "items": { "type": "string", "maxLength": 50 } },
              "ean": { "type": "array", "items": { "type": "string", "maxLength": 50 } },
              "mpn": { "type": "array", "items": { "type": "string", "maxLength": 100 } }
            }
          },
          "limit": { "type": "integer", "minimum": 1, "maximum": 50, "default": 10 },
          "currency": { "type": "string", "minLength": 3, "maxLength": 3, "examples": ["PLN"] },
          "locale": { "type": "string", "maxLength": 10, "examples": ["pl"] },
          "shipTo": { "$ref": "#/components/schemas/ShipTo" },
          "rankings": {
            "type": "array",
            "items": { "type": "string", "enum": ["cheapest", "best"] },
            "default": ["cheapest", "best"]
          },
          "bestWeights": {
            "type": "object",
            "description": "Weights for the `best` ranking. Applied only to that ranking.",
            "properties": {
              "sellerCredibility": { "type": "number", "minimum": 0, "maximum": 1 },
              "price": { "type": "number", "minimum": 0, "maximum": 1 },
              "deliverySpeed": { "type": "number", "minimum": 0, "maximum": 1 }
            }
          },
          "filters": {
            "type": "object",
            "properties": {
              "availability": { "type": "string", "enum": ["in_stock_only", "any"] }
            }
          }
        }
      },
      "SearchResponse": {
        "type": "object",
        "properties": {
          "requestId": { "type": "string" },
          "rankings": {
            "type": "object",
            "description": "One entry per requested ranking mode.",
            "additionalProperties": {
              "type": "object",
              "properties": {
                "offers": { "type": "array", "items": { "$ref": "#/components/schemas/Offer" } },
                "nextCursor": {
                  "type": ["string", "null"],
                  "description": "Opaque cursor for the next page, or null when the result set is exhausted. Send it back as `cursor` together with the SAME query and filters — a cursor issued for different parameters is ignored and the request is treated as a first page.\n\nImportant: ranking is applied within a page, not globally across all pages. Page 2 of `cheapest` is not guaranteed to be more expensive than page 1. Paging depth is capped at 500 results."
                }
              }
            }
          }
        }
      },
      "Execution": {
        "type": "object",
        "description": "Whether this merchant can be purchased from programmatically.",
        "properties": {
          "supported": { "type": "boolean" },
          "mode": { "type": ["string", "null"], "enum": ["api", "checkout_url", null] },
          "fallbackMode": { "type": "string", "const": "checkout_url" }
        }
      },
      "Offer": {
        "type": "object",
        "properties": {
          "offerId": { "type": "string", "examples": ["of_12345"] },
          "product": {
            "type": "object",
            "properties": {
              "id": { "type": "string", "examples": ["prod_987"] },
              "title": { "type": "string" },
              "identifiers": {
                "type": "object",
                "properties": {
                  "gtin": { "type": ["string", "null"] },
                  "mpn": { "type": ["string", "null"] }
                }
              },
              "imageUrl": { "type": ["string", "null"], "format": "uri" }
            }
          },
          "merchant": {
            "type": "object",
            "properties": {
              "id": { "type": "string", "examples": ["m_42"] },
              "name": { "type": "string" },
              "country": { "type": ["string", "null"] },
              "credibilityScore": {
                "type": "integer",
                "minimum": 0,
                "maximum": 255,
                "description": "Higher is more trusted. Defaults to 50 when unknown."
              },
              "website": { "type": ["string", "null"], "format": "uri" },
              "signals": {
                "type": "object",
                "properties": {
                  "ratingAvg": { "type": ["number", "null"] },
                  "ratingCount": { "type": "integer" }
                }
              }
            }
          },
          "pricing": {
            "type": "object",
            "properties": {
              "currency": { "type": "string" },
              "itemPrice": { "type": "number" },
              "shippingPrice": {
                "type": ["number", "null"],
                "description": "Not yet available; always null."
              },
              "taxEstimate": { "type": ["number", "null"], "description": "Not yet available; always null." },
              "dutiesEstimate": { "type": ["number", "null"], "description": "Not yet available; always null." },
              "historicalLow": {
                "type": ["number", "null"],
                "description": "Lowest price ever recorded for this product, in the response currency. Use it to judge whether the current price is actually a good one."
              },
              "historicalLowAt": { "type": ["string", "null"], "format": "date-time" },
              "historicalHigh": {
                "type": ["number", "null"],
                "description": "Highest price ever recorded for this product, in the response currency."
              },
              "historicalHighAt": { "type": ["string", "null"], "format": "date-time" },
              "percentAboveHistoricalLow": {
                "type": ["number", "null"],
                "description": "How far the current price sits above the historical low, in percent. 0 means the offer matches the record low."
              }
            }
          },
          "availability": {
            "type": "object",
            "properties": {
              "status": { "type": "string", "enum": ["in_stock", "out_of_stock"] },
              "quantity": { "type": ["integer", "null"] },
              "checkedAt": { "type": ["string", "null"], "format": "date-time" }
            }
          },
          "delivery": {
            "type": "object",
            "properties": {
              "type": { "type": "string", "examples": ["shipping"] },
              "minDays": { "type": ["integer", "null"] },
              "maxDays": { "type": ["integer", "null"] },
              "minDate": { "type": ["string", "null"], "format": "date" },
              "maxDate": { "type": ["string", "null"], "format": "date" }
            }
          },
          "execution": { "$ref": "#/components/schemas/Execution" },
          "links": {
            "type": "object",
            "properties": {
              "offerUrl": { "type": ["string", "null"], "format": "uri" },
              "checkoutUrl": { "type": ["string", "null"], "format": "uri" }
            }
          },
          "scores": {
            "type": ["object", "null"],
            "description": "Ranking components. Populated for the `best` ranking."
          }
        }
      }
    }
  }
}
