{
  "openapi": "3.1.0",
  "info": {
    "title": "Linklamp",
    "version": "1",
    "description": "An MSP describes a switch swap or repatch at a Dearborn, Michigan client site (and can paste its port map). The page drafts the visit scope: on-site duties, what the MSP's remote engineer keeps, exclusions (new electrical circuits or outlets, fire alarm systems, new cable runs, switch configuration) and the questions that change price or duration. Requesting the proposal records the requirement with a reference; Linklamp then emails a proposal with visit duties, exclusions, price and a proposed time. Nothing is booked or priced until the MSP accepts. The client's window can also be sent as an appointment request, which a provider confirms or not on its status page."
  },
  "servers": [
    {
      "url": "https://linklamp.meetinggrove.com"
    }
  ],
  "paths": {
    "/_c/requests/{id}": {
      "get": {
        "operationId": "request_status",
        "summary": "Resume your recorded requirement and linked offers",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "t",
            "in": "query",
            "required": true,
            "description": "Private receipt/link token. Never publish it.",
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{48}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Current customer-visible state; payment links are not proof of payment"
          },
          "400": {
            "description": "Invalid input"
          },
          "404": {
            "description": "Unknown resource or invalid credentials"
          },
          "409": {
            "description": "State or terms conflict"
          }
        }
      }
    },
    "/_c/offers/{id}": {
      "get": {
        "operationId": "inspect_offer",
        "summary": "Authorized terms, order and processor payment state",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "t",
            "in": "query",
            "required": true,
            "description": "Private receipt/link token. Never publish it.",
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{48}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Current customer-visible state; payment links are not proof of payment"
          },
          "400": {
            "description": "Invalid input"
          },
          "404": {
            "description": "Unknown resource or invalid credentials"
          },
          "409": {
            "description": "State or terms conflict"
          }
        }
      }
    },
    "/_c/offers/{id}/accept": {
      "post": {
        "operationId": "accept_offer",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "t",
            "in": "query",
            "required": true,
            "description": "Private receipt/link token. Never publish it.",
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{48}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "terms_sha256",
                  "accept",
                  "name"
                ],
                "properties": {
                  "terms_sha256": {
                    "type": "string",
                    "pattern": "^[0-9a-f]{64}$",
                    "description": "Exact terms_sha256 returned by inspect_offer"
                  },
                  "accept": {
                    "const": true
                  },
                  "name": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 120
                  },
                  "organization": {
                    "type": "string",
                    "maxLength": 160
                  },
                  "purchase_order": {
                    "type": "string",
                    "maxLength": 80
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Current customer-visible state; payment links are not proof of payment"
          },
          "400": {
            "description": "Invalid input"
          },
          "404": {
            "description": "Unknown resource or invalid credentials"
          },
          "409": {
            "description": "State or terms conflict"
          }
        }
      }
    },
    "/_c/offers/{id}/deliverable": {
      "get": {
        "operationId": "retrieve_deliverable",
        "summary": "The paid order's deliverable: exact text, SHA-256, version, sources and shortfall",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "t",
            "in": "query",
            "required": true,
            "description": "Private receipt/link token. Never publish it.",
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{48}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Current customer-visible state; payment links are not proof of payment"
          },
          "400": {
            "description": "Invalid input"
          },
          "404": {
            "description": "Unknown resource or invalid credentials"
          },
          "409": {
            "description": "State or terms conflict"
          }
        }
      }
    },
    "/_c/offers/{id}/decline": {
      "post": {
        "operationId": "decline_offer",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "t",
            "in": "query",
            "required": true,
            "description": "Private receipt/link token. Never publish it.",
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{48}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "terms_sha256"
                ],
                "properties": {
                  "terms_sha256": {
                    "type": "string",
                    "pattern": "^[0-9a-f]{64}$",
                    "description": "Exact terms_sha256 returned by inspect_offer"
                  },
                  "reason": {
                    "type": "string",
                    "maxLength": 500
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Current customer-visible state; payment links are not proof of payment"
          },
          "400": {
            "description": "Invalid input"
          },
          "404": {
            "description": "Unknown resource or invalid credentials"
          },
          "409": {
            "description": "State or terms conflict"
          }
        }
      }
    },
    "/_c/offers/{id}/release": {
      "post": {
        "operationId": "release_payment",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "t",
            "in": "query",
            "required": true,
            "description": "Private receipt/link token. Never publish it.",
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{48}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "terms_sha256",
                  "payment",
                  "confirm"
                ],
                "properties": {
                  "terms_sha256": {
                    "type": "string",
                    "pattern": "^[0-9a-f]{64}$",
                    "description": "Exact terms_sha256 returned by inspect_offer"
                  },
                  "payment": {
                    "type": "string"
                  },
                  "confirm": {
                    "const": true
                  },
                  "name": {
                    "type": "string",
                    "maxLength": 120
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Current customer-visible state; payment links are not proof of payment"
          },
          "400": {
            "description": "Invalid input"
          },
          "404": {
            "description": "Unknown resource or invalid credentials"
          },
          "409": {
            "description": "State or terms conflict"
          }
        }
      }
    },
    "/_c/offers/{id}/counter": {
      "post": {
        "operationId": "counter_offer",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "t",
            "in": "query",
            "required": true,
            "description": "Private receipt/link token. Never publish it.",
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{48}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "terms_sha256",
                  "proposal",
                  "name"
                ],
                "properties": {
                  "terms_sha256": {
                    "type": "string",
                    "pattern": "^[0-9a-f]{64}$",
                    "description": "Exact terms_sha256 returned by inspect_offer"
                  },
                  "name": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 120
                  },
                  "organization": {
                    "type": "string",
                    "maxLength": 160
                  },
                  "agent": {
                    "type": "string",
                    "maxLength": 120,
                    "description": "Your agent's name, if you want it recorded with the act"
                  },
                  "proposal": {
                    "type": "object",
                    "minProperties": 1,
                    "description": "A proposal, not a change: the terms stand until the business issues a revised offer",
                    "properties": {
                      "quantities": {
                        "type": "array",
                        "minItems": 1,
                        "items": {
                          "type": "object",
                          "required": [
                            "item",
                            "quantity"
                          ],
                          "properties": {
                            "item": {
                              "type": "integer",
                              "minimum": 0,
                              "description": "0-based index into terms.items"
                            },
                            "quantity": {
                              "type": "number",
                              "exclusiveMinimum": 0
                            }
                          }
                        }
                      },
                      "counterparties": {
                        "type": "array",
                        "minItems": 1,
                        "maxItems": 25,
                        "items": {
                          "type": "object",
                          "required": [
                            "name"
                          ],
                          "properties": {
                            "name": {
                              "type": "string",
                              "minLength": 2,
                              "maxLength": 160
                            },
                            "country": {
                              "type": "string",
                              "pattern": "^[A-Za-z]{2}$"
                            },
                            "identifier": {
                              "type": "string",
                              "maxLength": 40
                            }
                          }
                        }
                      },
                      "deliver_by": {
                        "type": "string",
                        "format": "date"
                      },
                      "total_minor": {
                        "type": "integer",
                        "minimum": 1
                      },
                      "payment": {
                        "type": "object",
                        "required": [
                          "kind"
                        ],
                        "properties": {
                          "kind": {
                            "enum": [
                              "CHECKOUT_FULL",
                              "INVOICE"
                            ]
                          },
                          "days_until_due": {
                            "type": "integer",
                            "minimum": 0,
                            "maximum": 90
                          }
                        }
                      },
                      "note": {
                        "type": "string",
                        "maxLength": 1000
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Current customer-visible state; payment links are not proof of payment"
          },
          "400": {
            "description": "Invalid input"
          },
          "404": {
            "description": "Unknown resource or invalid credentials"
          },
          "409": {
            "description": "State or terms conflict"
          }
        }
      }
    },
    "/_c/offers/{id}/purchase-order": {
      "post": {
        "operationId": "submit_purchase_order",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "t",
            "in": "query",
            "required": true,
            "description": "Private receipt/link token. Never publish it.",
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{48}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "terms_sha256",
                  "po",
                  "name"
                ],
                "properties": {
                  "terms_sha256": {
                    "type": "string",
                    "pattern": "^[0-9a-f]{64}$",
                    "description": "Exact terms_sha256 returned by inspect_offer"
                  },
                  "name": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 120
                  },
                  "organization": {
                    "type": "string",
                    "maxLength": 160
                  },
                  "agent": {
                    "type": "string",
                    "maxLength": 120,
                    "description": "Your agent's name, if you want it recorded with the act"
                  },
                  "po": {
                    "type": "object",
                    "required": [
                      "number",
                      "lines",
                      "total_minor",
                      "currency",
                      "payment_terms_days"
                    ],
                    "description": "Matched against the accepted terms; differences are shown as exceptions",
                    "properties": {
                      "number": {
                        "type": "string",
                        "pattern": "^[A-Za-z0-9._/-]{1,60}$"
                      },
                      "revision": {
                        "type": "integer",
                        "minimum": 1,
                        "default": 1
                      },
                      "buyer_vendor_id": {
                        "type": "string",
                        "maxLength": 80
                      },
                      "lines": {
                        "type": "array",
                        "minItems": 1,
                        "maxItems": 40,
                        "items": {
                          "type": "object",
                          "required": [
                            "description",
                            "quantity",
                            "unit_price_minor",
                            "amount_minor"
                          ],
                          "properties": {
                            "description": {
                              "type": "string",
                              "maxLength": 300
                            },
                            "quantity": {
                              "type": "number",
                              "minimum": 0
                            },
                            "unit_price_minor": {
                              "type": "integer",
                              "minimum": 0
                            },
                            "amount_minor": {
                              "type": "integer",
                              "minimum": 0
                            }
                          }
                        }
                      },
                      "total_minor": {
                        "type": "integer",
                        "minimum": 0
                      },
                      "currency": {
                        "type": "string",
                        "pattern": "^[A-Z]{3}$"
                      },
                      "payment_terms_days": {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 120
                      },
                      "bill_to": {
                        "type": "string",
                        "maxLength": 300
                      },
                      "invoice_route": {
                        "type": "string",
                        "maxLength": 300
                      },
                      "document_sha256": {
                        "type": "string",
                        "pattern": "^[0-9a-f]{64}$"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Current customer-visible state; payment links are not proof of payment"
          },
          "400": {
            "description": "Invalid input"
          },
          "404": {
            "description": "Unknown resource or invalid credentials"
          },
          "409": {
            "description": "State or terms conflict"
          }
        }
      }
    },
    "/_c/offers/{id}/purchasing-requirements": {
      "post": {
        "operationId": "state_purchasing_requirements",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "t",
            "in": "query",
            "required": true,
            "description": "Private receipt/link token. Never publish it.",
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{48}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "terms_sha256",
                  "requirements",
                  "name",
                  "organization"
                ],
                "properties": {
                  "terms_sha256": {
                    "type": "string",
                    "pattern": "^[0-9a-f]{64}$",
                    "description": "Exact terms_sha256 returned by inspect_offer"
                  },
                  "name": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 120
                  },
                  "organization": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 160
                  },
                  "agent": {
                    "type": "string",
                    "maxLength": 120,
                    "description": "Your agent's name, if you want it recorded with the act"
                  },
                  "requirements": {
                    "type": "object",
                    "required": [
                      "vendor_approval_required",
                      "purchase_order_required"
                    ],
                    "properties": {
                      "vendor_approval_required": {
                        "type": "boolean"
                      },
                      "purchase_order_required": {
                        "type": "boolean"
                      },
                      "documents_required": {
                        "type": "array",
                        "maxItems": 12,
                        "items": {
                          "type": "string",
                          "maxLength": 80
                        }
                      },
                      "buyer_vendor_id": {
                        "type": "string",
                        "maxLength": 80
                      },
                      "route": {
                        "type": "string",
                        "maxLength": 300
                      },
                      "payment_terms_days": {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 120
                      },
                      "note": {
                        "type": "string",
                        "maxLength": 1000
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Current customer-visible state; payment links are not proof of payment"
          },
          "400": {
            "description": "Invalid input"
          },
          "404": {
            "description": "Unknown resource or invalid credentials"
          },
          "409": {
            "description": "State or terms conflict"
          }
        }
      }
    },
    "/_c/offers/{id}/vendor-status": {
      "post": {
        "operationId": "report_vendor_status",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "t",
            "in": "query",
            "required": true,
            "description": "Private receipt/link token. Never publish it.",
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{48}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "terms_sha256",
                  "status",
                  "reference",
                  "name",
                  "organization"
                ],
                "properties": {
                  "terms_sha256": {
                    "type": "string",
                    "pattern": "^[0-9a-f]{64}$",
                    "description": "Exact terms_sha256 returned by inspect_offer"
                  },
                  "name": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 120
                  },
                  "organization": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 160
                  },
                  "agent": {
                    "type": "string",
                    "maxLength": 120,
                    "description": "Your agent's name, if you want it recorded with the act"
                  },
                  "status": {
                    "enum": [
                      "APPROVED",
                      "DOCUMENTS_REQUESTED",
                      "REJECTED"
                    ]
                  },
                  "reference": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 200
                  },
                  "buyer_vendor_id": {
                    "type": "string",
                    "maxLength": 80
                  },
                  "documents_requested": {
                    "type": "array",
                    "maxItems": 12,
                    "items": {
                      "type": "string",
                      "maxLength": 80
                    }
                  },
                  "note": {
                    "type": "string",
                    "maxLength": 1000
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Current customer-visible state; payment links are not proof of payment"
          },
          "400": {
            "description": "Invalid input"
          },
          "404": {
            "description": "Unknown resource or invalid credentials"
          },
          "409": {
            "description": "State or terms conflict"
          }
        }
      }
    },
    "/_c/offers/{id}/inspection": {
      "post": {
        "operationId": "inspect_delivery",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "t",
            "in": "query",
            "required": true,
            "description": "Private receipt/link token. Never publish it.",
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{48}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "terms_sha256",
                  "lines",
                  "name"
                ],
                "properties": {
                  "terms_sha256": {
                    "type": "string",
                    "pattern": "^[0-9a-f]{64}$",
                    "description": "Exact terms_sha256 returned by inspect_offer"
                  },
                  "name": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 120
                  },
                  "organization": {
                    "type": "string",
                    "maxLength": 160
                  },
                  "agent": {
                    "type": "string",
                    "maxLength": 120,
                    "description": "Your agent's name, if you want it recorded with the act"
                  },
                  "lines": {
                    "type": "array",
                    "minItems": 1,
                    "items": {
                      "type": "object",
                      "required": [
                        "item",
                        "accepted_quantity",
                        "rejected_quantity"
                      ],
                      "properties": {
                        "item": {
                          "type": "integer",
                          "minimum": 0
                        },
                        "accepted_quantity": {
                          "type": "number",
                          "minimum": 0
                        },
                        "rejected_quantity": {
                          "type": "number",
                          "minimum": 0
                        },
                        "reason": {
                          "type": "string",
                          "maxLength": 300
                        }
                      }
                    }
                  },
                  "portion": {
                    "type": "string",
                    "maxLength": 40
                  },
                  "note": {
                    "type": "string",
                    "maxLength": 1000
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Current customer-visible state; payment links are not proof of payment"
          },
          "400": {
            "description": "Invalid input"
          },
          "404": {
            "description": "Unknown resource or invalid credentials"
          },
          "409": {
            "description": "State or terms conflict"
          }
        }
      }
    },
    "/_c/offers/{id}/remedy": {
      "post": {
        "operationId": "answer_remedy",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "t",
            "in": "query",
            "required": true,
            "description": "Private receipt/link token. Never publish it.",
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{48}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "terms_sha256",
                  "remedy_id",
                  "answer",
                  "name"
                ],
                "properties": {
                  "terms_sha256": {
                    "type": "string",
                    "pattern": "^[0-9a-f]{64}$",
                    "description": "Exact terms_sha256 returned by inspect_offer"
                  },
                  "name": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 120
                  },
                  "organization": {
                    "type": "string",
                    "maxLength": 160
                  },
                  "agent": {
                    "type": "string",
                    "maxLength": 120,
                    "description": "Your agent's name, if you want it recorded with the act"
                  },
                  "remedy_id": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "answer": {
                    "enum": [
                      "ACCEPT",
                      "DECLINE"
                    ]
                  },
                  "note": {
                    "type": "string",
                    "maxLength": 1000
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Current customer-visible state; payment links are not proof of payment"
          },
          "400": {
            "description": "Invalid input"
          },
          "404": {
            "description": "Unknown resource or invalid credentials"
          },
          "409": {
            "description": "State or terms conflict"
          }
        }
      }
    },
    "/_c/request": {
      "post": {
        "operationId": "submit_request",
        "summary": "Send a requirement to Linklamp",
        "description": "The request is recorded with a reference at once. Linklamp reads the scope, open questions and any words kept as written, then prices and schedules the visit and emails a proposal: visit duties, exclusions, price and a proposed time inside the client's window. Without an email address the request is still recorded, reply_by_email is listed in missing_specifications, and no proposal can be sent until an address is given in a continuation. Nothing is ordered, booked or committed until the buyer agrees terms; a time is confirmed only on the appointment status page, after a provider confirms it. Contact details are kept apart from the requirement, while we correspond or do business and for 24 months after, so a later request picks up where it left off; ask us to delete them at any time.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "need"
                ],
                "properties": {
                  "continuation": {
                    "type": "object",
                    "required": [
                      "id",
                      "token"
                    ],
                    "description": "Optional receipt credentials to continue an existing requirement with this business",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "token": {
                        "type": "string"
                      }
                    }
                  },
                  "action": {
                    "type": "string",
                    "enum": [
                      "buy",
                      "source",
                      "quote",
                      "verify",
                      "lease",
                      "license",
                      "hire",
                      "retrieve",
                      "convert",
                      "other"
                    ],
                    "description": "What you want done"
                  },
                  "need": {
                    "type": "string",
                    "maxLength": 2000,
                    "description": "The requirement in your own words"
                  },
                  "specifications": {
                    "type": "object",
                    "properties": {
                      "site_zip": {
                        "type": "string",
                        "maxLength": 10,
                        "description": "ZIP code of the client site in Dearborn, MI (48120, 48121, 48123, 48124, 48126, 48128).",
                        "x-facet": "geography"
                      },
                      "site_kind": {
                        "type": "string",
                        "maxLength": 80,
                        "description": "Kind of site, in your words (dental office, warehouse).",
                        "x-facet": "specification"
                      },
                      "site_text": {
                        "type": "string",
                        "maxLength": 200,
                        "description": "The site as you would describe it to the person on site.",
                        "x-facet": "geography"
                      },
                      "job_type": {
                        "type": "string",
                        "enum": [
                          "switch_swap",
                          "repatch",
                          "trace_and_label",
                          "mixed",
                          "not_stated"
                        ],
                        "description": "What the visit does. mixed when more than one applies; say which in job_text.",
                        "x-facet": "specification"
                      },
                      "job_text": {
                        "type": "string",
                        "maxLength": 80,
                        "description": "The job in words, for example Switch swap, or Trace, label and repatch.",
                        "x-facet": "specification"
                      },
                      "port_count": {
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 400,
                        "description": "Ports on the switch (or the switch being replaced).",
                        "x-facet": "quantity"
                      },
                      "panel_layout": {
                        "type": "string",
                        "maxLength": 80,
                        "description": "Patch panels as count x ports, for example 2 x 24.",
                        "x-facet": "quantity"
                      },
                      "rack_text": {
                        "type": "string",
                        "maxLength": 120,
                        "description": "The rack and where the switch goes, in words: 2-post rack, switch in U3.",
                        "x-facet": "specification"
                      },
                      "poe": {
                        "type": "boolean",
                        "description": "true when PoE devices (phones, APs, cameras) are on the switch. Leave it out when not known; it is not read as a no.",
                        "x-facet": "specification"
                      },
                      "port_map_state": {
                        "type": "string",
                        "enum": [
                          "HAVE",
                          "PARTIAL",
                          "NONE",
                          "UNKNOWN"
                        ],
                        "description": "Whether an authoritative port map exists. NONE adds a trace-and-label stage.",
                        "x-facet": "specification"
                      },
                      "port_map_rows": {
                        "type": "string",
                        "maxLength": 8000,
                        "description": "Port map rows as text: port or range, device, PoE, VLAN. One row per line or separated by semicolons.",
                        "x-facet": "specification"
                      },
                      "replacement_state": {
                        "type": "string",
                        "enum": [
                          "ON_SITE",
                          "SHIPPING",
                          "NOT_YET",
                          "UNKNOWN"
                        ],
                        "description": "Where the replacement switch is.",
                        "x-facet": "specification"
                      },
                      "preconfigured": {
                        "type": "boolean",
                        "description": "Whether the replacement arrives pre-configured.",
                        "x-facet": "specification"
                      },
                      "hardware_arrival": {
                        "type": "string",
                        "format": "date",
                        "description": "Date the replacement reaches the site, YYYY-MM-DD. Delivery, not the visit date. A value in words is kept as sent and listed in missing_specifications; put words in hardware_arrival_text instead.",
                        "x-facet": "timing"
                      },
                      "hardware_arrival_text": {
                        "type": "string",
                        "maxLength": 200,
                        "description": "The arrival as you wrote it when it is not a full date (Thursday, next Wednesday).",
                        "x-facet": "timing"
                      },
                      "client_window_text": {
                        "type": "string",
                        "maxLength": 300,
                        "description": "The window the client allows, in words (Saturday 9-12, Thursday after 6pm, sometime next week). A preference, not a booking.",
                        "x-facet": "timing"
                      },
                      "preferred_start": {
                        "type": "string",
                        "format": "date",
                        "description": "A visit date the client accepts, YYYY-MM-DD, only when there is one. While the window is still words (sometime next week), leave it out and use client_window_text; it is then listed in missing_specifications. A value in words here is kept as sent, listed in missing_specifications, and the request is not called dated. A preference only; the proposal proposes the time.",
                        "x-facet": "timing"
                      },
                      "signoff_by": {
                        "type": "string",
                        "maxLength": 80,
                        "description": "Who signs off remotely (your engineer's first name).",
                        "x-facet": "identifier"
                      },
                      "signoff_channel": {
                        "type": "string",
                        "maxLength": 80,
                        "description": "Bridge for the visit: Teams, Zoom, Google Meet, phone bridge.",
                        "x-facet": "specification"
                      },
                      "access_notes": {
                        "type": "string",
                        "maxLength": 500,
                        "description": "Who lets the person on site in, keys, escort, parking. Never an alarm code.",
                        "x-facet": "specification"
                      },
                      "old_switch": {
                        "type": "string",
                        "enum": [
                          "KEEP_ON_SITE",
                          "KEEP_MOUNTED",
                          "TAKE_AWAY",
                          "UNKNOWN"
                        ],
                        "description": "What happens to the old switch. KEEP_MOUNTED keeps it racked until signoff for rollback.",
                        "x-facet": "specification"
                      },
                      "boundaries_noted": {
                        "type": "string",
                        "maxLength": 400,
                        "description": "Items outside the visit that this job touches, in words: new outlet or circuit (your client's electrician); fire alarm dialer (left exactly as it is); new cable drops (a separate item); switch configuration and VLANs (your engineer).",
                        "x-facet": "specification"
                      },
                      "exclusions": {
                        "type": "string",
                        "maxLength": 300,
                        "description": "What no visit includes: new circuits or outlets, anything on the fire alarm system, new cable runs (priced separately only when asked), switch configuration.",
                        "x-facet": "specification"
                      },
                      "reply_by_email": {
                        "type": "boolean",
                        "description": "true when contact.email is sent with this request (or is on file from the request it continues). Required: while it is absent it is listed in missing_specifications, and no proposal can be emailed until an address is given in a continuation.",
                        "x-facet": "identifier"
                      },
                      "new_drops": {
                        "type": "string",
                        "maxLength": 300,
                        "description": "New cable drops asked for; scoped as a separate item.",
                        "x-facet": "specification"
                      },
                      "additional_sites": {
                        "type": "string",
                        "maxLength": 300,
                        "description": "Other sites mentioned. Coverage and travel terms are set in the proposal.",
                        "x-facet": "geography"
                      },
                      "open_questions": {
                        "type": "string",
                        "maxLength": 4000,
                        "description": "Questions that change the visit, each with its owner.",
                        "x-facet": "specification"
                      },
                      "unread_text": {
                        "type": "string",
                        "maxLength": 4000,
                        "description": "Your words not yet read into a field; kept as written.",
                        "x-facet": "specification"
                      },
                      "original_note": {
                        "type": "string",
                        "maxLength": 6000,
                        "description": "The job as you wrote it.",
                        "x-facet": "specification"
                      }
                    },
                    "description": "Details you already know. The business helps resolve missing specifications in the continuing engagement."
                  },
                  "quantity": {
                    "type": "object",
                    "properties": {
                      "amount": {
                        "type": "number"
                      },
                      "unit": {
                        "type": "string"
                      },
                      "per": {
                        "type": "string"
                      }
                    }
                  },
                  "timing": {
                    "type": "object",
                    "properties": {
                      "earliest": {
                        "type": "string"
                      },
                      "latest": {
                        "type": "string"
                      },
                      "recurrence": {
                        "type": "string"
                      },
                      "text": {
                        "type": "string"
                      }
                    }
                  },
                  "geography": {
                    "type": "object",
                    "properties": {
                      "text": {
                        "type": "string"
                      },
                      "country": {
                        "type": "string"
                      },
                      "from": {
                        "type": "string"
                      },
                      "to": {
                        "type": "string"
                      }
                    }
                  },
                  "budget": {
                    "type": "object",
                    "properties": {
                      "amount": {
                        "type": "number"
                      },
                      "currency": {
                        "type": "string",
                        "description": "ISO 4217, default USD"
                      },
                      "per": {
                        "type": "string",
                        "description": "total, unit, month, year, load, ..."
                      }
                    }
                  },
                  "requested_fields": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "maxItems": 30,
                    "description": "Result fields you need"
                  },
                  "contact": {
                    "type": "object",
                    "description": "Optional; stored apart from the requirement, kept while we correspond or do business and for 24 months after, then deleted; you can ask us to delete it sooner",
                    "properties": {
                      "email": {
                        "type": "string"
                      },
                      "name": {
                        "type": "string"
                      },
                      "organization": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Recorded, with a reference number"
          },
          "400": {
            "description": "What to fix"
          }
        }
      }
    },
    "/_c/availability": {
      "get": {
        "operationId": "check_availability",
        "summary": "Times a provider has published for a service, if any",
        "parameters": [
          {
            "name": "service",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "closet-visit"
              ]
            }
          },
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "to",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "mode REQUESTED_WINDOWS (no published times: state preferred windows) or PROVIDER_CALENDAR with open slots"
          }
        }
      }
    },
    "/_c/appointments": {
      "post": {
        "operationId": "request_appointment",
        "summary": "Ask for an appointment. The answer is a request (or a short hold on a published time); it is confirmed only when the provider confirms.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "service",
                  "need",
                  "client_key",
                  "timezone"
                ],
                "properties": {
                  "service": {
                    "type": "string",
                    "enum": [
                      "closet-visit"
                    ]
                  },
                  "need": {
                    "type": "string",
                    "maxLength": 2000
                  },
                  "preferred": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "required": [
                        "start",
                        "end"
                      ],
                      "properties": {
                        "start": {
                          "type": "string",
                          "format": "date-time",
                          "description": "ISO time with its offset"
                        },
                        "end": {
                          "type": "string",
                          "format": "date-time"
                        }
                      }
                    },
                    "maxItems": 6
                  },
                  "slot_id": {
                    "type": "string"
                  },
                  "minutes": {
                    "type": "integer",
                    "description": "How long, where the service lets the buyer choose (its duration_minutes to max_duration_minutes); a provider confirms that length"
                  },
                  "timezone": {
                    "type": "string",
                    "description": "Your IANA time zone, for display"
                  },
                  "client_key": {
                    "type": "string",
                    "description": "Your idempotency key: the same key twice is one request"
                  },
                  "specifications": {
                    "type": "object"
                  },
                  "geography": {
                    "type": "object"
                  },
                  "contact": {
                    "type": "object",
                    "properties": {
                      "email": {
                        "type": "string"
                      },
                      "name": {
                        "type": "string"
                      },
                      "organization": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Requested or held, with a status link"
          },
          "409": {
            "description": "That time is no longer offered"
          }
        }
      }
    },
    "/_c/appointments/{id}": {
      "get": {
        "operationId": "appointment_status",
        "summary": "The current state of a request and its history",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "t",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "State and history"
          }
        }
      }
    },
    "/_c/appointments/{id}/cancel": {
      "post": {
        "operationId": "cancel_appointment",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "t",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "reason": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Current state and history"
          },
          "404": {
            "description": "Unknown appointment or invalid token"
          },
          "409": {
            "description": "State conflict"
          }
        }
      }
    },
    "/_c/appointments/{id}/reschedule": {
      "post": {
        "operationId": "reschedule_appointment",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "t",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "preferred"
                ],
                "properties": {
                  "preferred": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 6,
                    "items": {
                      "type": "object",
                      "required": [
                        "start",
                        "end"
                      ],
                      "properties": {
                        "start": {
                          "type": "string",
                          "format": "date-time",
                          "description": "ISO time with its offset"
                        },
                        "end": {
                          "type": "string",
                          "format": "date-time"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Current state and history"
          },
          "404": {
            "description": "Unknown appointment or invalid token"
          },
          "409": {
            "description": "State conflict"
          }
        }
      }
    }
  }
}