{
 "openapi": "3.1.0",
 "info": {
  "title": "Water Damage Ranked feed",
  "version": "1",
  "description": "Ranked lists and business facts, each with its source and date, as static JSON. Every item carries how the site ranks; nobody can pay to rank."
 },
 "servers": [
  {
   "url": "https://waterdamageranked.com"
  }
 ],
 "paths": {
  "/feed.json": {
   "get": {
    "operationId": "catalog",
    "summary": "Every list and business page and its feed item",
    "responses": {
     "200": {
      "description": "The site's DataCatalog",
      "content": {
       "application/ld+json": {
        "schema": {
         "type": "object"
        }
       }
      }
     }
    }
   }
  },
  "/{page}/index.json": {
   "get": {
    "operationId": "item",
    "summary": "One page's feed item",
    "parameters": [
     {
      "name": "page",
      "in": "path",
      "required": true,
      "description": "The page's path from the catalog, without its slashes at the ends (tx/austin)",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "A page's feed item: its schema.org JSON-LD (an ItemList for a ranked list or a city hub, a LocalBusiness for a business page) with the site's ranking method. Never a phone number.",
      "content": {
       "application/ld+json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "404": {
      "description": "No such page"
     }
    }
   }
  },
  "/v1/agent/consent": {
   "get": {
    "operationId": "consent",
    "servers": [
     {
      "url": "https://ranked-intake.dustin-243.workers.dev"
     }
    ],
    "summary": "The words the person must accept before an agent sends their request",
    "parameters": [
     {
      "name": "domain",
      "in": "query",
      "required": true,
      "schema": {
       "const": "waterdamageranked.com"
      }
     },
     {
      "name": "language",
      "in": "query",
      "schema": {
       "type": "string",
       "enum": [
        "en",
        "es"
       ]
      }
     }
    ],
    "responses": {
     "200": {
      "description": "The consent: its version, its words and their sha256",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "consent": {
           "type": "object",
           "properties": {
            "version": {
             "type": "string"
            },
            "language": {
             "type": "string"
            },
            "text": {
             "type": "string"
            },
            "sha256": {
             "type": "string"
            }
           }
          }
         }
        }
       }
      }
     },
     "404": {
      "description": "No such site",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     }
    }
   }
  },
  "/v1/agent/request": {
   "post": {
    "operationId": "request",
    "servers": [
     {
      "url": "https://ranked-intake.dustin-243.workers.dev"
     }
    ],
    "summary": "Request a provider for a person",
    "description": "Ask Water Damage Ranked to connect a person with a provider for a job in a city: a business from this site or the best available. Only after the person accepted the consent words (/v1/agent/consent) at their version: without that nothing is stored. A request sent by an agent is never sold to a business until the owner's counsel has confirmed its consent; until then it goes to us alone. Limits apply per agent, per address and per phone number, and the same request again returns the first one's id.",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "domain",
         "language",
         "job",
         "city",
         "zip",
         "business",
         "person",
         "agent",
         "consent"
        ],
        "properties": {
         "domain": {
          "type": "string",
          "const": "waterdamageranked.com"
         },
         "language": {
          "type": "string",
          "enum": [
           "en",
           "es"
          ],
          "description": "The person's language"
         },
         "job": {
          "type": "string",
          "maxLength": 500,
          "description": "What the person needs done, in their words"
         },
         "city": {
          "type": "string",
          "description": "The city's list page on this site, from the catalog (/tx/austin/)"
         },
         "zip": {
          "type": "string",
          "pattern": "^[0-9]{5}$",
          "description": "The person's ZIP code"
         },
         "business": {
          "type": "string",
          "description": "The chosen business's page on this site, from the catalog, or best_available"
         },
         "person": {
          "type": "object",
          "required": [
           "name",
           "phone"
          ],
          "properties": {
           "name": {
            "type": "string"
           },
           "phone": {
            "type": "string",
            "description": "A US number"
           }
          }
         },
         "agent": {
          "type": "object",
          "required": [
           "name"
          ],
          "properties": {
           "name": {
            "type": "string",
            "maxLength": 80,
            "description": "Who is asking: the agent's own name"
           },
           "url": {
            "type": "string",
            "description": "An https page about the agent"
           }
          }
         },
         "consent": {
          "type": "object",
          "required": [
           "version",
           "sha256",
           "accepted"
          ],
          "description": "The person accepted the words from /v1/agent/consent, sent back as given",
          "properties": {
           "version": {
            "type": "string"
           },
           "sha256": {
            "type": "string"
           },
           "accepted": {
            "type": "boolean",
            "const": true
           }
          }
         },
         "test": {
          "type": "boolean",
          "description": "Stored and held: nobody is contacted"
         }
        }
       }
      }
     }
    },
    "responses": {
     "202": {
      "description": "Received: its request_id and what happens next",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "200": {
      "description": "The same request again: the first one's request_id",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "400": {
      "description": "A field is missing or wrong: errors names each",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "403": {
      "description": "This contact can't be taken",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "428": {
      "description": "Consent needed: the words to show the person",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "consent": {
           "type": "object",
           "properties": {
            "version": {
             "type": "string"
            },
            "language": {
             "type": "string"
            },
            "text": {
             "type": "string"
            },
            "sha256": {
             "type": "string"
            }
           }
          }
         }
        }
       }
      }
     },
     "413": {
      "description": "The body is over 4096 bytes",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "415": {
      "description": "The body is not JSON (Content-Type: application/json)",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "429": {
      "description": "Too many requests: Retry-After says when",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "503": {
      "description": "Not recorded: our store is unavailable; send the same request again in a minute",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     }
    }
   }
  }
 }
}
