{
  "openapi": "3.1.0",
  "info": {
    "title": "Waterbear Microscope observation requests",
    "version": "1.0.0",
    "description": "Free observation request submission for human review. payment_supported=false and device_operation_available=false; payment and live device control are planned but unavailable. No public read, booking, payment, or device operation is exposed."
  },
  "servers": [
    {
      "url": "https://waterbear-microscope.pages.dev"
    }
  ],
  "paths": {
    "/api/demands": {
      "post": {
        "operationId": "submitObservationRequest",
        "summary": "Submit one user-approved free observation request for human review",
        "description": "Agents must show the exact request and obtain explicit user consent before calling this operation. A successful response confirms request receipt only, not a booking, quote, availability, or completed observation.",
        "security": [],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9._:-]{8,100}$"
            },
            "description": "Required. Reuse the same key with the unchanged body when retrying uncertain delivery. A changed normalized body returns 409. The value is trimmed."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "sample",
                  "conditions",
                  "budget"
                ],
                "anyOf": [
                  {
                    "required": [
                      "desired_result"
                    ]
                  },
                  {
                    "required": [
                      "result"
                    ]
                  }
                ],
                "properties": {
                  "sample": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 300,
                    "description": "Required, nonempty after trimming. Values are NFC normalized; length is measured in JavaScript UTF-16 code units."
                  },
                  "conditions": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 2000,
                    "description": "Required, nonempty after trimming. Use Not specified if the user has no condition."
                  },
                  "desired_result": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 2000,
                    "description": "Required, nonempty after trimming. Use Not specified if the user has no desired result."
                  },
                  "result": {
                    "type": "string",
                    "maxLength": 2000,
                    "description": "Legacy alias used only when desired_result is absent. Prefer desired_result."
                  },
                  "budget": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200,
                    "description": "Required, nonempty after trimming. Use Not specified if the user has no budget."
                  },
                  "email": {
                    "type": "string",
                    "maxLength": 254,
                    "pattern": "^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$",
                    "description": "Optional. Include only with user approval. A valid email is required if quote_requested is true, unless the legacy contact field is used."
                  },
                  "contact": {
                    "type": "string",
                    "maxLength": 254,
                    "description": "Legacy alias used only when email is absent. Prefer email; this value may satisfy the quote email requirement."
                  },
                  "quote_requested": {
                    "type": "boolean",
                    "description": "Only JSON true requests a quote and requires a valid email. Records interest only; no quote is created."
                  },
                  "interest": {
                    "type": "string",
                    "maxLength": 64,
                    "enum": [
                      "",
                      "free_explore",
                      "fresh_capture",
                      "china_collection_observation",
                      "custom_observation",
                      "multi_condition_experiment",
                      "shanghai_moss_safari",
                      "moss_microcosm",
                      "tardigrade_search",
                      "chinese_bracket_fungus",
                      "chinese_tea",
                      "spices_under_the_microscope",
                      "common_plant_leaf",
                      "legal_special_plant",
                      "chinese_silk",
                      "xuan_paper",
                      "traditional_fibers",
                      "ordinary_paper_comparison"
                    ],
                    "description": "Optional. Use only a listed interest value."
                  },
                  "website": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Spam honeypot. Omit or leave empty; a nonempty value is rejected."
                  }
                },
                "additionalProperties": true,
                "description": "Unknown properties are ignored. Strings are trimmed and Unicode NFC normalized; field length limits count JavaScript UTF-16 code units. The complete UTF-8 JSON body must not exceed 8192 bytes."
              }
            }
          }
        },
        "x-rate-limits": {
          "validated_nonduplicate_attempts_per_ip_per_fixed_utc_hour": 5,
          "saved_requests_globally_per_utc_day": 200,
          "identical_retries_checked_before_hourly_limit": true
        },
        "responses": {
          "200": {
            "description": "Identical request already received; no new request was created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReceivedRequest"
                },
                "example": {
                  "received": true,
                  "duplicate": true,
                  "status": "PENDING_REVIEW"
                }
              }
            }
          },
          "201": {
            "description": "Request received for human review only.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReceivedRequest"
                },
                "example": {
                  "received": true,
                  "duplicate": false,
                  "status": "PENDING_REVIEW"
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON or fields, invalid Idempotency-Key, or quote_email_required."
          },
          "405": {
            "description": "Method not allowed. Only POST is supported; OPTIONS is available for CORS preflight."
          },
          "409": {
            "description": "The Idempotency-Key was already used with different normalized content."
          },
          "413": {
            "description": "Request body exceeds 8192 bytes."
          },
          "415": {
            "description": "Content-Type must be application/json."
          },
          "422": {
            "description": "Safety screening rejected the request. Do not retry to evade screening."
          },
          "429": {
            "description": "Hourly IP limit or global daily saved-request limit reached."
          },
          "503": {
            "description": "Service unavailable or request save failed; receipt is unconfirmed."
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "ReceivedRequest": {
        "type": "object",
        "required": [
          "received",
          "duplicate",
          "status"
        ],
        "properties": {
          "received": {
            "const": true
          },
          "duplicate": {
            "type": "boolean"
          },
          "status": {
            "const": "PENDING_REVIEW"
          }
        }
      }
    }
  },
  "x-waterbear-capabilities": {
    "request_submission_supported": true,
    "payment_supported": false,
    "payment_status": "planned_unavailable",
    "device_operation_available": false,
    "device_operation_status": "planned_unavailable"
  }
}
