{
 "$schema": "https://json-schema.org/draft/2020-12/schema",
 "$id": "https://caliperpress.com/api/schema/object_slice.json",
 "title": "Record file (object_slice)",
 "description": "data.json of a record page /<section>/objects/<record>/: the record, every check in history, the latest check, indicators, changes and the raw journal.",
 "type": "object",
 "additionalProperties": false,
 "required": [
  "schema",
  "schema_version",
  "object",
  "section",
  "description",
  "latest",
  "history",
  "indicators",
  "generated_at",
  "events",
  "raw_journal",
  "quarantine",
  "held_value"
 ],
 "properties": {
  "schema": {
   "const": "object_slice"
  },
  "schema_version": {
   "const": "1"
  },
  "object": {
   "$ref": "#/$defs/object",
   "description": "What is tracked: name, section and the provider page we read."
  },
  "section": {
   "type": "string",
   "pattern": "^[a-z0-9-]+$",
   "description": "Section of the site, as in the address."
  },
  "description": {
   "type": "object",
   "description": "Description of the section's records: name, unit and method edition."
  },
  "latest": {
   "anyOf": [
    {
     "$ref": "#/$defs/measurement"
    },
    {
     "type": "null"
    }
   ],
   "description": "The last confirmed check of the main question; newer checks that recorded no value are in held_value."
  },
  "history": {
   "type": "array",
   "items": {
    "$ref": "#/$defs/measurement"
   },
   "description": "Every check of the record, oldest first, up to and including latest."
  },
  "indicators": {
   "type": "array",
   "items": {
    "$ref": "#/$defs/indicator"
   },
   "description": "Values calculated from the checks, each with its window and sample size."
  },
  "generated_at": {
   "type": "string",
   "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}\\.[0-9]{3}Z$",
   "description": "When the file was built, ISO 8601 in UTC."
  },
  "events": {
   "type": "array",
   "items": {
    "$ref": "#/$defs/event"
   },
   "description": "Confirmed changes, each with the old and new value."
  },
  "raw_journal": {
   "type": "array",
   "items": {
    "$ref": "#/$defs/event"
   },
   "description": "Moves that were not counted as changes, with the reason."
  },
  "quarantine": {
   "$ref": "#/$defs/quarantine",
   "description": "Large price moves held back until a repeat check confirms them."
  },
  "held_value": {
   "$ref": "#/$defs/held_value",
   "description": "Questions whose last confirmed value is shown while newer checks recorded no value."
  },
  "billing": {
   "$ref": "#/$defs/billing",
   "description": "How the first term is paid, as the provider's page states it."
  }
 },
 "$defs": {
  "time": {
   "type": "string",
   "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}\\.[0-9]{3}Z$"
  },
  "unit": {
   "type": "string",
   "pattern": "^(?:ai_credits_per_month|answer|answers_per_day|blocked_agents|boolean|characters_per_month|completions_per_month|count|credits_per_month|date|days|devices|files_per_chat|flow_credits|fraction|gb_per_user|hours|hours_per_month|index_points|million_tokens|minutes|minutes_per_month|ms|not_determined|page_currency_per_month|percent|requests_per_minute|text|thousand_tokens|times_base_plan|tokens|tokens_per_minute|usd_per_1000_characters|usd_per_1m_tokens|usd_per_hour|usd_per_token|video_minutes_per_month|words|words_per_month|(?:usd|eur|chf|gbp)_per_(?:month|year|hour|day|page|credit|minute|token|1m_tokens|1000_characters|[0-9]+_(?:months|pages|credits|characters|minutes|tokens|hours|words)))(?:; (?:ai_credits_per_month|answer|answers_per_day|blocked_agents|boolean|characters_per_month|completions_per_month|count|credits_per_month|date|days|devices|files_per_chat|flow_credits|fraction|gb_per_user|hours|hours_per_month|index_points|million_tokens|minutes|minutes_per_month|ms|not_determined|page_currency_per_month|percent|requests_per_minute|text|thousand_tokens|times_base_plan|tokens|tokens_per_minute|usd_per_1000_characters|usd_per_1m_tokens|usd_per_hour|usd_per_token|video_minutes_per_month|words|words_per_month|(?:usd|eur|chf|gbp)_per_(?:month|year|hour|day|page|credit|minute|token|1m_tokens|1000_characters|[0-9]+_(?:months|pages|credits|characters|minutes|tokens|hours|words))))*$"
  },
  "measurement": {
   "type": "object",
   "additionalProperties": false,
   "required": [
    "schema",
    "schema_version",
    "measurement_id",
    "section",
    "section_version",
    "object_id",
    "question",
    "claim",
    "measured",
    "data_status",
    "reason",
    "time",
    "region",
    "repeats",
    "method_version",
    "evidence",
    "extra",
    "region_name"
   ],
   "properties": {
    "schema": {
     "const": "measurement"
    },
    "schema_version": {
     "const": "1"
    },
    "measurement_id": {
     "type": "string",
     "pattern": "^[0-9a-f]{16}$",
     "description": "Stable id of one check."
    },
    "section": {
     "type": "string",
     "pattern": "^[a-z0-9-]+$",
     "description": "Section of the site, as in the address."
    },
    "section_version": {
     "type": "string",
     "minLength": 1,
     "description": "Version of the section's checking rules."
    },
    "object_id": {
     "type": "string",
     "pattern": "^[a-z0-9-]+:[a-z0-9._-]+$",
     "description": "Record id: <section>:<record>."
    },
    "question": {
     "type": "string",
     "minLength": 8,
     "maxLength": 300,
     "description": "What the check answers, in plain words."
    },
    "claim": {
     "type": [
      "object",
      "null"
     ],
     "additionalProperties": false,
     "required": [
      "value",
      "unit",
      "source",
      "date"
     ],
     "properties": {
      "value": {
       "type": [
        "string",
        "null"
       ],
       "pattern": "^-?[0-9]+(\\.[0-9]+)?$",
       "description": "Decimal string, such as \"2.99\"; null when unknown."
      },
      "text": {
       "type": [
        "string",
        "null"
       ],
       "maxLength": 500,
       "description": "The answer in words, when the value is not a number."
      },
      "unit": {
       "type": "string",
       "pattern": "^(?:ai_credits_per_month|answer|answers_per_day|blocked_agents|boolean|characters_per_month|completions_per_month|count|credits_per_month|date|days|devices|files_per_chat|flow_credits|fraction|gb_per_user|hours|hours_per_month|index_points|million_tokens|minutes|minutes_per_month|ms|not_determined|page_currency_per_month|percent|requests_per_minute|text|thousand_tokens|times_base_plan|tokens|tokens_per_minute|usd_per_1000_characters|usd_per_1m_tokens|usd_per_hour|usd_per_token|video_minutes_per_month|words|words_per_month|(?:usd|eur|chf|gbp)_per_(?:month|year|hour|day|page|credit|minute|token|1m_tokens|1000_characters|[0-9]+_(?:months|pages|credits|characters|minutes|tokens|hours|words)))(?:; (?:ai_credits_per_month|answer|answers_per_day|blocked_agents|boolean|characters_per_month|completions_per_month|count|credits_per_month|date|days|devices|files_per_chat|flow_credits|fraction|gb_per_user|hours|hours_per_month|index_points|million_tokens|minutes|minutes_per_month|ms|not_determined|page_currency_per_month|percent|requests_per_minute|text|thousand_tokens|times_base_plan|tokens|tokens_per_minute|usd_per_1000_characters|usd_per_1m_tokens|usd_per_hour|usd_per_token|video_minutes_per_month|words|words_per_month|(?:usd|eur|chf|gbp)_per_(?:month|year|hour|day|page|credit|minute|token|1m_tokens|1000_characters|[0-9]+_(?:months|pages|credits|characters|minutes|tokens|hours|words))))*$",
       "description": "Unit code, such as usd_per_month."
      },
      "currency": {
       "type": "string",
       "pattern": "^[A-Z]{3}$",
       "description": "ISO 4217 currency of a money unit."
      },
      "source": {
       "type": [
        "object",
        "null"
       ],
       "additionalProperties": false,
       "required": [
        "url",
        "quote"
       ],
       "properties": {
        "url": {
         "type": [
          "string",
          "null"
         ],
         "pattern": "^https?://"
        },
        "url_note": {
         "type": "string",
         "description": "Why the address is withheld."
        },
        "quote": {
         "type": [
          "string",
          "null"
         ],
         "maxLength": 1000
        }
       }
      },
      "date": {
       "type": [
        "string",
        "null"
       ],
       "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$"
      }
     },
     "description": "What the provider's page states, with its source and a short quote; null when the page states nothing."
    },
    "measured": {
     "type": "object",
     "additionalProperties": false,
     "required": [
      "value",
      "unit"
     ],
     "properties": {
      "value": {
       "type": [
        "string",
        "null"
       ],
       "pattern": "^-?[0-9]+(\\.[0-9]+)?$",
       "description": "Decimal string, such as \"2.99\"; null when unknown."
      },
      "text": {
       "type": [
        "string",
        "null"
       ],
       "maxLength": 500,
       "description": "The answer in words, when the value is not a number."
      },
      "unit": {
       "type": "string",
       "pattern": "^(?:ai_credits_per_month|answer|answers_per_day|blocked_agents|boolean|characters_per_month|completions_per_month|count|credits_per_month|date|days|devices|files_per_chat|flow_credits|fraction|gb_per_user|hours|hours_per_month|index_points|million_tokens|minutes|minutes_per_month|ms|not_determined|page_currency_per_month|percent|requests_per_minute|text|thousand_tokens|times_base_plan|tokens|tokens_per_minute|usd_per_1000_characters|usd_per_1m_tokens|usd_per_hour|usd_per_token|video_minutes_per_month|words|words_per_month|(?:usd|eur|chf|gbp)_per_(?:month|year|hour|day|page|credit|minute|token|1m_tokens|1000_characters|[0-9]+_(?:months|pages|credits|characters|minutes|tokens|hours|words)))(?:; (?:ai_credits_per_month|answer|answers_per_day|blocked_agents|boolean|characters_per_month|completions_per_month|count|credits_per_month|date|days|devices|files_per_chat|flow_credits|fraction|gb_per_user|hours|hours_per_month|index_points|million_tokens|minutes|minutes_per_month|ms|not_determined|page_currency_per_month|percent|requests_per_minute|text|thousand_tokens|times_base_plan|tokens|tokens_per_minute|usd_per_1000_characters|usd_per_1m_tokens|usd_per_hour|usd_per_token|video_minutes_per_month|words|words_per_month|(?:usd|eur|chf|gbp)_per_(?:month|year|hour|day|page|credit|minute|token|1m_tokens|1000_characters|[0-9]+_(?:months|pages|credits|characters|minutes|tokens|hours|words))))*$",
       "description": "Unit code, such as usd_per_month."
      },
      "currency": {
       "type": "string",
       "pattern": "^[A-Z]{3}$",
       "description": "ISO 4217 currency of a money unit."
      },
      "range": {
       "type": [
        "object",
        "null"
       ],
       "additionalProperties": false,
       "required": [
        "min",
        "max"
       ],
       "properties": {
        "min": {
         "type": [
          "string",
          "null"
         ],
         "pattern": "^-?[0-9]+(\\.[0-9]+)?$"
        },
        "max": {
         "type": [
          "string",
          "null"
         ],
         "pattern": "^-?[0-9]+(\\.[0-9]+)?$"
        }
       },
       "description": "Lowest and highest contribution to the index, as decimal strings; null when unknown."
      }
     },
     "description": "The value this check recorded."
    },
    "data_status": {
     "type": "string",
     "enum": [
      "measured",
      "stated_by_source",
      "calculated",
      "unknown"
     ],
     "description": "measured, stated_by_source, calculated or unknown."
    },
    "reason": {
     "type": [
      "string",
      "null"
     ],
     "maxLength": 500,
     "description": "Why the value is unknown or why the entry was not counted."
    },
    "time": {
     "type": "string",
     "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}\\.[0-9]{3}Z$",
     "description": "Time of the check, ISO 8601 in UTC."
    },
    "region": {
     "type": "string",
     "pattern": "^[A-Z]{2}$",
     "description": "Two-letter code of the country the value was shown in."
    },
    "region_name": {
     "type": "string",
     "minLength": 1,
     "description": "Name of that country."
    },
    "repeats": {
     "type": "integer",
     "minimum": 0,
     "description": "Number of repeat readings in the check."
    },
    "method_version": {
     "type": "string",
     "minLength": 1,
     "description": "Edition of the method used for this check."
    },
    "evidence": {
     "type": [
      "object",
      "null"
     ],
     "additionalProperties": false,
     "required": [
      "url"
     ],
     "properties": {
      "url": {
       "type": [
        "string",
        "null"
       ]
      },
      "url_note": {
       "type": "string",
       "description": "Why the address is withheld."
      },
      "http_status": {
       "type": [
        "integer",
        "null"
       ]
      },
      "bytes": {
       "type": [
        "integer",
        "null"
       ],
       "minimum": 0
      }
     },
     "description": "The page we read: address, size in bytes and HTTP status."
    },
    "data_class": {
     "type": "string",
     "enum": [
      "public",
      "restricted",
      "secret"
     ]
    },
    "extra": {
     "type": "object"
    }
   }
  },
  "object": {
   "type": "object",
   "additionalProperties": false,
   "required": [
    "schema",
    "schema_version",
    "object_id",
    "section",
    "name",
    "url",
    "category",
    "affiliate",
    "extra"
   ],
   "properties": {
    "schema": {
     "const": "object"
    },
    "schema_version": {
     "const": "1"
    },
    "object_id": {
     "type": "string",
     "pattern": "^[a-z0-9-]+:[a-z0-9._-]+$",
     "description": "Record id: <section>:<record>."
    },
    "section": {
     "type": "string",
     "pattern": "^[a-z0-9-]+$",
     "description": "Section of the site, as in the address."
    },
    "name": {
     "type": "string",
     "minLength": 1,
     "maxLength": 200
    },
    "name_zh": {
     "type": [
      "string",
      "null"
     ],
     "maxLength": 200
    },
    "url": {
     "type": [
      "string",
      "null"
     ],
     "pattern": "^https?://"
    },
    "url_note": {
     "type": "string",
     "description": "Why the address is withheld."
    },
    "category": {
     "type": "string",
     "minLength": 1
    },
    "country": {
     "type": [
      "string",
      "null"
     ],
     "pattern": "^[A-Z]{2}$"
    },
    "affiliate": {
     "type": "null",
     "description": "Always null: the site has no affiliate links."
    },
    "extra": {
     "type": "object"
    }
   }
  },
  "indicator": {
   "type": "object",
   "additionalProperties": false,
   "required": [
    "code",
    "value",
    "unit",
    "data_status",
    "reason",
    "n",
    "window"
   ],
   "properties": {
    "code": {
     "type": "string",
     "pattern": "^[a-z0-9_]+$"
    },
    "value": {
     "type": [
      "string",
      "null"
     ],
     "pattern": "^-?[0-9]+(\\.[0-9]+)?$",
     "description": "Decimal string, such as \"2.99\"; null when unknown."
    },
    "unit": {
     "type": "string",
     "pattern": "^(?:ai_credits_per_month|answer|answers_per_day|blocked_agents|boolean|characters_per_month|completions_per_month|count|credits_per_month|date|days|devices|files_per_chat|flow_credits|fraction|gb_per_user|hours|hours_per_month|index_points|million_tokens|minutes|minutes_per_month|ms|not_determined|page_currency_per_month|percent|requests_per_minute|text|thousand_tokens|times_base_plan|tokens|tokens_per_minute|usd_per_1000_characters|usd_per_1m_tokens|usd_per_hour|usd_per_token|video_minutes_per_month|words|words_per_month|(?:usd|eur|chf|gbp)_per_(?:month|year|hour|day|page|credit|minute|token|1m_tokens|1000_characters|[0-9]+_(?:months|pages|credits|characters|minutes|tokens|hours|words)))(?:; (?:ai_credits_per_month|answer|answers_per_day|blocked_agents|boolean|characters_per_month|completions_per_month|count|credits_per_month|date|days|devices|files_per_chat|flow_credits|fraction|gb_per_user|hours|hours_per_month|index_points|million_tokens|minutes|minutes_per_month|ms|not_determined|page_currency_per_month|percent|requests_per_minute|text|thousand_tokens|times_base_plan|tokens|tokens_per_minute|usd_per_1000_characters|usd_per_1m_tokens|usd_per_hour|usd_per_token|video_minutes_per_month|words|words_per_month|(?:usd|eur|chf|gbp)_per_(?:month|year|hour|day|page|credit|minute|token|1m_tokens|1000_characters|[0-9]+_(?:months|pages|credits|characters|minutes|tokens|hours|words))))*$",
     "description": "Unit code, such as usd_per_month."
    },
    "currency": {
     "type": "string",
     "pattern": "^[A-Z]{3}$",
     "description": "ISO 4217 currency of a money unit."
    },
    "data_status": {
     "type": "string",
     "enum": [
      "measured",
      "stated_by_source",
      "calculated",
      "unknown"
     ],
     "description": "measured, stated_by_source, calculated or unknown."
    },
    "reason": {
     "type": [
      "string",
      "null"
     ],
     "description": "Why the value is unknown or why the entry was not counted."
    },
    "n": {
     "type": "integer",
     "minimum": 0
    },
    "window": {
     "type": [
      "string",
      "null"
     ]
    },
    "description_en": {
     "type": [
      "string",
      "null"
     ],
     "maxLength": 300
    }
   }
  },
  "event": {
   "type": "object",
   "additionalProperties": false,
   "required": [
    "event_id",
    "type",
    "status",
    "object_id",
    "section",
    "question",
    "old",
    "new",
    "unit",
    "old_text",
    "new_text",
    "change_percent",
    "first_seen",
    "confirmed_at",
    "plan",
    "why_it_matters",
    "measurement_before",
    "measurement_after",
    "measurement_confirming",
    "letter_worthy"
   ],
   "properties": {
    "event_id": {
     "type": "string",
     "pattern": "^[0-9a-f]{16}$"
    },
    "type": {
     "type": "string",
     "enum": [
      "price_change",
      "value_change",
      "wording_change",
      "terms_change",
      "added"
     ]
    },
    "status": {
     "type": "string",
     "description": "confirmed for events; in raw_journal, why the move was not counted (for example pending, unconfirmed_jump, quarantine, quarantine_rejected)."
    },
    "object_id": {
     "type": "string",
     "pattern": "^[a-z0-9-]+:[a-z0-9._-]+$",
     "description": "Record id: <section>:<record>."
    },
    "section": {
     "type": "string",
     "description": "Section of the site, as in the address."
    },
    "question": {
     "type": [
      "string",
      "null"
     ],
     "description": "What the check answers, in plain words."
    },
    "old": {
     "type": [
      "string",
      "null"
     ],
     "description": "Old value: decimal string or the answer in words."
    },
    "new": {
     "type": [
      "string",
      "null"
     ],
     "description": "New value; null while a held move waits for its repeat check."
    },
    "unit": {
     "type": [
      "string",
      "null"
     ],
     "pattern": "^(?:ai_credits_per_month|answer|answers_per_day|blocked_agents|boolean|characters_per_month|completions_per_month|count|credits_per_month|date|days|devices|files_per_chat|flow_credits|fraction|gb_per_user|hours|hours_per_month|index_points|million_tokens|minutes|minutes_per_month|ms|not_determined|page_currency_per_month|percent|requests_per_minute|text|thousand_tokens|times_base_plan|tokens|tokens_per_minute|usd_per_1000_characters|usd_per_1m_tokens|usd_per_hour|usd_per_token|video_minutes_per_month|words|words_per_month|(?:usd|eur|chf|gbp)_per_(?:month|year|hour|day|page|credit|minute|token|1m_tokens|1000_characters|[0-9]+_(?:months|pages|credits|characters|minutes|tokens|hours|words)))(?:; (?:ai_credits_per_month|answer|answers_per_day|blocked_agents|boolean|characters_per_month|completions_per_month|count|credits_per_month|date|days|devices|files_per_chat|flow_credits|fraction|gb_per_user|hours|hours_per_month|index_points|million_tokens|minutes|minutes_per_month|ms|not_determined|page_currency_per_month|percent|requests_per_minute|text|thousand_tokens|times_base_plan|tokens|tokens_per_minute|usd_per_1000_characters|usd_per_1m_tokens|usd_per_hour|usd_per_token|video_minutes_per_month|words|words_per_month|(?:usd|eur|chf|gbp)_per_(?:month|year|hour|day|page|credit|minute|token|1m_tokens|1000_characters|[0-9]+_(?:months|pages|credits|characters|minutes|tokens|hours|words))))*$",
     "description": "Unit code, such as usd_per_month."
    },
    "currency": {
     "type": "string",
     "pattern": "^[A-Z]{3}$",
     "description": "ISO 4217 currency of a money unit."
    },
    "old_text": {
     "type": [
      "string",
      "null"
     ]
    },
    "new_text": {
     "type": [
      "string",
      "null"
     ]
    },
    "change_percent": {
     "type": [
      "number",
      "null"
     ]
    },
    "first_seen": {
     "type": [
      "string",
      "null"
     ],
     "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}\\.[0-9]{3}Z$"
    },
    "confirmed_at": {
     "type": [
      "string",
      "null"
     ],
     "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}\\.[0-9]{3}Z$"
    },
    "region": {
     "type": [
      "string",
      "null"
     ],
     "pattern": "^[A-Z]{2}$",
     "description": "Two-letter code of the country the value was shown in."
    },
    "region_name": {
     "type": "string",
     "description": "Name of that country."
    },
    "plan": {
     "type": [
      "string",
      "null"
     ]
    },
    "why_it_matters": {
     "type": [
      "string",
      "null"
     ]
    },
    "measurement_before": {
     "type": [
      "string",
      "null"
     ],
     "pattern": "^[0-9a-f]{16}$"
    },
    "measurement_after": {
     "type": [
      "string",
      "null"
     ],
     "pattern": "^[0-9a-f]{16}$"
    },
    "measurement_confirming": {
     "type": [
      "string",
      "null"
     ],
     "pattern": "^[0-9a-f]{16}$"
    },
    "letter_worthy": {
     "type": "boolean"
    },
    "main_answer": {
     "type": "boolean"
    },
    "reason": {
     "type": "string",
     "description": "Why the value is unknown or why the entry was not counted."
    },
    "direction": {
     "type": "string"
    },
    "value_withheld": {
     "const": true
    }
   }
  },
  "quarantine": {
   "type": "object",
   "additionalProperties": false,
   "required": [
    "active",
    "main_answer",
    "rule",
    "held"
   ],
   "properties": {
    "active": {
     "type": "boolean"
    },
    "main_answer": {
     "type": "boolean"
    },
    "rule": {
     "type": "string"
    },
    "held": {
     "type": "array",
     "items": {
      "type": "object",
      "additionalProperties": false,
      "required": [
       "measurement_id",
       "question",
       "unit",
       "time",
       "status",
       "direction",
       "shown_measurement_id",
       "main_answer"
      ],
      "properties": {
       "measurement_id": {
        "type": "string",
        "pattern": "^[0-9a-f]{16}$",
        "description": "Stable id of one check."
       },
       "question": {
        "type": [
         "string",
         "null"
        ],
        "description": "What the check answers, in plain words."
       },
       "unit": {
        "type": [
         "string",
         "null"
        ],
        "pattern": "^(?:ai_credits_per_month|answer|answers_per_day|blocked_agents|boolean|characters_per_month|completions_per_month|count|credits_per_month|date|days|devices|files_per_chat|flow_credits|fraction|gb_per_user|hours|hours_per_month|index_points|million_tokens|minutes|minutes_per_month|ms|not_determined|page_currency_per_month|percent|requests_per_minute|text|thousand_tokens|times_base_plan|tokens|tokens_per_minute|usd_per_1000_characters|usd_per_1m_tokens|usd_per_hour|usd_per_token|video_minutes_per_month|words|words_per_month|(?:usd|eur|chf|gbp)_per_(?:month|year|hour|day|page|credit|minute|token|1m_tokens|1000_characters|[0-9]+_(?:months|pages|credits|characters|minutes|tokens|hours|words)))(?:; (?:ai_credits_per_month|answer|answers_per_day|blocked_agents|boolean|characters_per_month|completions_per_month|count|credits_per_month|date|days|devices|files_per_chat|flow_credits|fraction|gb_per_user|hours|hours_per_month|index_points|million_tokens|minutes|minutes_per_month|ms|not_determined|page_currency_per_month|percent|requests_per_minute|text|thousand_tokens|times_base_plan|tokens|tokens_per_minute|usd_per_1000_characters|usd_per_1m_tokens|usd_per_hour|usd_per_token|video_minutes_per_month|words|words_per_month|(?:usd|eur|chf|gbp)_per_(?:month|year|hour|day|page|credit|minute|token|1m_tokens|1000_characters|[0-9]+_(?:months|pages|credits|characters|minutes|tokens|hours|words))))*$",
        "description": "Unit code, such as usd_per_month."
       },
       "currency": {
        "type": "string",
        "pattern": "^[A-Z]{3}$",
        "description": "ISO 4217 currency of a money unit."
       },
       "time": {
        "type": "string",
        "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}\\.[0-9]{3}Z$",
        "description": "Time of the check, ISO 8601 in UTC."
       },
       "status": {
        "type": "string",
        "enum": [
         "quarantine",
         "quarantine_rejected"
        ]
       },
       "direction": {
        "type": "string"
       },
       "shown_measurement_id": {
        "type": [
         "string",
         "null"
        ],
        "pattern": "^[0-9a-f]{16}$"
       },
       "main_answer": {
        "type": "boolean"
       },
       "value_withheld": {
        "const": true
       }
      }
     }
    }
   }
  },
  "held_value": {
   "type": "object",
   "additionalProperties": false,
   "required": [
    "active",
    "main_answer",
    "rule",
    "questions"
   ],
   "properties": {
    "active": {
     "type": "boolean"
    },
    "main_answer": {
     "type": "boolean"
    },
    "rule": {
     "type": "string"
    },
    "questions": {
     "type": "array",
     "items": {
      "type": "object",
      "additionalProperties": false,
      "required": [
       "question",
       "main_answer",
       "shown_measurement_id",
       "last_confirmed",
       "latest_check",
       "hours_since_confirmed",
       "failed_checks"
      ],
      "properties": {
       "question": {
        "type": "string",
        "description": "What the check answers, in plain words."
       },
       "main_answer": {
        "type": "boolean"
       },
       "shown_measurement_id": {
        "type": [
         "string",
         "null"
        ],
        "pattern": "^[0-9a-f]{16}$"
       },
       "last_confirmed": {
        "type": [
         "string",
         "null"
        ],
        "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}\\.[0-9]{3}Z$"
       },
       "latest_check": {
        "type": [
         "string",
         "null"
        ],
        "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}\\.[0-9]{3}Z$"
       },
       "hours_since_confirmed": {
        "type": [
         "number",
         "null"
        ]
       },
       "failed_checks": {
        "type": "array",
        "items": {
         "type": "object",
         "additionalProperties": false,
         "required": [
          "measurement_id",
          "time",
          "status",
          "reason"
         ],
         "properties": {
          "measurement_id": {
           "type": [
            "string",
            "null"
           ],
           "pattern": "^[0-9a-f]{16}$",
           "description": "Stable id of one check."
          },
          "time": {
           "type": [
            "string",
            "null"
           ],
           "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}\\.[0-9]{3}Z$",
           "description": "Time of the check, ISO 8601 in UTC."
          },
          "status": {
           "type": [
            "string",
            "null"
           ]
          },
          "reason": {
           "type": [
            "string",
            "null"
           ],
           "description": "Why the value is unknown or why the entry was not counted."
          }
         }
        }
       }
      }
     }
    }
   }
  },
  "billing": {
   "type": "object",
   "additionalProperties": false,
   "required": [
    "method",
    "minimum_term_months",
    "source",
    "quote",
    "checked"
   ],
   "properties": {
    "method": {
     "type": "string"
    },
    "minimum_term_months": {
     "type": [
      "integer",
      "null"
     ],
     "minimum": 0
    },
    "source": {
     "type": "string"
    },
    "quote": {
     "type": [
      "string",
      "null"
     ]
    },
    "checked": {
     "type": [
      "string",
      "null"
     ],
     "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}\\.[0-9]{3}Z$"
    },
    "first_payment": {
     "type": [
      "string",
      "null"
     ],
     "pattern": "^-?[0-9]+(\\.[0-9]+)?$"
    },
    "currency": {
     "type": [
      "string",
      "null"
     ],
     "pattern": "^[A-Z]{3}$",
     "description": "ISO 4217 currency of a money unit."
    }
   }
  },
  "object_slice": {
   "type": "object",
   "additionalProperties": false,
   "required": [
    "schema",
    "schema_version",
    "object",
    "section",
    "description",
    "latest",
    "history",
    "indicators",
    "generated_at",
    "events",
    "raw_journal",
    "quarantine",
    "held_value"
   ],
   "properties": {
    "schema": {
     "const": "object_slice"
    },
    "schema_version": {
     "const": "1"
    },
    "object": {
     "$ref": "#/$defs/object",
     "description": "What is tracked: name, section and the provider page we read."
    },
    "section": {
     "type": "string",
     "pattern": "^[a-z0-9-]+$",
     "description": "Section of the site, as in the address."
    },
    "description": {
     "type": "object",
     "description": "Description of the section's records: name, unit and method edition."
    },
    "latest": {
     "anyOf": [
      {
       "$ref": "#/$defs/measurement"
      },
      {
       "type": "null"
      }
     ],
     "description": "The last confirmed check of the main question; newer checks that recorded no value are in held_value."
    },
    "history": {
     "type": "array",
     "items": {
      "$ref": "#/$defs/measurement"
     },
     "description": "Every check of the record, oldest first, up to and including latest."
    },
    "indicators": {
     "type": "array",
     "items": {
      "$ref": "#/$defs/indicator"
     },
     "description": "Values calculated from the checks, each with its window and sample size."
    },
    "generated_at": {
     "type": "string",
     "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}\\.[0-9]{3}Z$",
     "description": "When the file was built, ISO 8601 in UTC."
    },
    "events": {
     "type": "array",
     "items": {
      "$ref": "#/$defs/event"
     },
     "description": "Confirmed changes, each with the old and new value."
    },
    "raw_journal": {
     "type": "array",
     "items": {
      "$ref": "#/$defs/event"
     },
     "description": "Moves that were not counted as changes, with the reason."
    },
    "quarantine": {
     "$ref": "#/$defs/quarantine",
     "description": "Large price moves held back until a repeat check confirms them."
    },
    "held_value": {
     "$ref": "#/$defs/held_value",
     "description": "Questions whose last confirmed value is shown while newer checks recorded no value."
    },
    "billing": {
     "$ref": "#/$defs/billing",
     "description": "How the first term is paid, as the provider's page states it."
    }
   }
  }
 }
}