Offer Schema

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "https://local-loop-io.github.io/projects/loop-protocol/schemas/v0.2.0/offer.schema.json",
  "title": "Offer",
  "description": "Offer schema — LOOP v0.2.0",
  "type": "object",
  "required": [
    "@context",
    "@type",
    "schema_version",
    "id",
    "from_city",
    "to_city",
    "quantity",
    "status",
    "available_until"
  ],
  "anyOf": [
    {
      "required": [
        "material_id"
      ]
    },
    {
      "required": [
        "product_id"
      ]
    }
  ],
  "properties": {
    "@context": {
      "description": "JSON-LD context",
      "type": "string",
      "enum": [
        "https://local-loop-io.github.io/projects/loop-protocol/contexts/loop-v0.1.1.jsonld",
        "https://local-loop-io.github.io/projects/loop-protocol/contexts/loop-v0.2.0.jsonld"
      ]
    },
    "@type": {
      "description": "Object type identifier",
      "type": "string",
      "const": "Offer"
    },
    "schema_version": {
      "description": "Schema version for the interop flow. Emitters SHOULD use 0.2.0; receivers SHOULD accept additive minor/patch releases.",
      "type": "string",
      "pattern": "^0\\.[1-9]\\d*\\.\\d+$",
      "examples": [
        "0.1.1",
        "0.2.0"
      ]
    },
    "id": {
      "description": "Offer identifier",
      "type": "string",
      "pattern": "^[A-Z0-9-]{8,}$",
      "examples": [
        "OFR-2F7A6B9C"
      ]
    },
    "material_id": {
      "description": "MaterialDNA identifier (required if no product_id)",
      "type": "string",
      "pattern": "^MAT-[A-Z]{2}-[A-Z]{3}-\\d{4}-[A-Z]+-[A-Z0-9]{6,}$",
      "examples": [
        "MAT-DE-MUC-2025-PLASTIC-B847F3"
      ]
    },
    "product_id": {
      "description": "ProductDNA identifier (required if no material_id)",
      "type": "string",
      "pattern": "^PRD-[A-Z0-9-]{8,}$",
      "examples": [
        "PRD-DE-MUC-2025-DESK-F4A7B2"
      ]
    },
    "from_city": {
      "description": "City offering the material",
      "type": "string",
      "minLength": 2,
      "maxLength": 80,
      "examples": [
        "Munich"
      ]
    },
    "to_city": {
      "description": "Target city or 'any' for open offers",
      "type": "string",
      "minLength": 2,
      "maxLength": 80,
      "examples": [
        "Berlin"
      ]
    },
    "quantity": {
      "description": "Amount offered",
      "type": "object",
      "required": [
        "value",
        "unit"
      ],
      "properties": {
        "value": {
          "type": "number",
          "minimum": 0,
          "examples": [
            800
          ]
        },
        "unit": {
          "type": "string",
          "enum": [
            "kg",
            "g",
            "t",
            "l",
            "ml",
            "m3",
            "piece",
            "bundle"
          ],
          "examples": [
            "kg"
          ]
        }
      }
    },
    "status": {
      "description": "Offer status",
      "type": "string",
      "enum": [
        "open",
        "reserved",
        "withdrawn"
      ]
    },
    "available_until": {
      "description": "Offer expiry time (ISO 8601)",
      "type": "string",
      "format": "date-time",
      "examples": [
        "2025-06-05T10:00:00Z"
      ]
    },
    "terms": {
      "description": "Optional commercial or logistics terms",
      "type": "string",
      "maxLength": 280,
      "examples": [
        "Ready for pickup within 48 hours"
      ]
    },
    "metadata": {
      "description": "Additional metadata",
      "type": "object",
      "additionalProperties": true
    }
  }
}