{
  "openapi": "3.1.0",
  "info": {
    "title": "zpe-reviews",
    "version": "0.3.1",
    "description": "Verified reviews for zpe.vc/reviews. A review exists only where a purchase exists, and the sale is the proof. Nothing collected here is sold, and nothing is inferred about a person who did not write."
  },
  "servers": [
    {
      "url": "/reviews",
      "description": "zpe-reviews on zpe.vc"
    }
  ],
  "paths": {
    "/_/api/v1/reviews": {
      "get": {
        "operationId": "getReviews",
        "summary": "Every review this account holds, newest first, with what verified it and its state",
        "tags": [
          "reviews"
        ],
        "responses": {
          "200": {
            "description": "The reviews this account holds, newest first, each with the state it is in and the purchase that verified it.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "The credential is missing, or the door did not recognise it.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "This key may not do that: it is granted a different app, or the door named no account to scope the request to.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests: this key has spent its request ceiling. Retry after the period the answer names.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "This app failed while answering",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "A service this app needs did not answer, so the request could not be checked.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/_/api/v1/wall": {
      "get": {
        "operationId": "getWall",
        "summary": "The two populations and their counts, with the gap published only above the minimum sample",
        "tags": [
          "wall"
        ],
        "parameters": [
          {
            "name": "business",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Both populations and their counts, with the gap present only above the minimum sample.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "`business` is required: name the business by its public id, `?business=<id>`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "The credential is missing, or the door did not recognise it.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "This key may not do that: it is granted a different app, or the door named no account to scope the request to.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "No business with that public id belongs to this account.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests: this key has spent its request ceiling. Retry after the period the answer names.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "This app failed while answering",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "A service this app needs did not answer, so the request could not be checked.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/_/api/v1/erasures": {
      "post": {
        "operationId": "postErasures",
        "summary": "Honour an erasure request by the person's address: the contact record goes, the review becomes a tombstone, one event records it",
        "tags": [
          "erasure"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "business",
                  "contact"
                ],
                "properties": {
                  "business": {
                    "type": "string"
                  },
                  "contact": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The erasure was honoured — `{erased, classes, reviews, replies}` — or, for `dry_run`, `{dry_run, would_erase, reviews, replies}`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The request could not be read: a JSON body naming `business` and `contact` is required.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "The credential is missing, or the door did not recognise it.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "This key may not do that: it is granted a different app, or the door named no account to scope the request to.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "No business with that public id belongs to this account.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "No record for that address now: nothing under this business matches it, which is also what an erasure already honoured looks like. The record is gone and this API keeps no marker of who was erased.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests: this key has spent its request ceiling, or this account has used its write allowance for the hour.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "This app failed while answering",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "A service this app needs did not answer, so the request could not be checked.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/_/api/v1/replies/forward": {
      "post": {
        "operationId": "postRepliesForward",
        "summary": "Turn the copy of a tenant's replies on or off and say where it goes. The stored inbox is never affected",
        "tags": [
          "replies"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "business",
                  "enabled"
                ],
                "properties": {
                  "business": {
                    "type": "string"
                  },
                  "forward_to": {
                    "type": "string"
                  },
                  "enabled": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The setting was stored: `{ok, enabled, forward_to}`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The request could not be read: a JSON body naming `business` and `enabled` is required, and a forward needs a full address to copy replies to.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "The credential is missing, or the door did not recognise it.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "This key may not do that: it is granted a different app, or the door named no account to scope the request to.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "No business with that public id belongs to this account.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests: this key has spent its request ceiling, or this account has used its write allowance for the hour.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "This app failed while answering",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "A service this app needs did not answer, so the request could not be checked.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/_/api/v1/appeals": {
      "post": {
        "operationId": "postAppeals",
        "summary": "Decide a removal appeal. Refused when the deciding principal is the one who removed it, so the chain shows two signatures",
        "tags": [
          "moderation"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "review",
                  "decision"
                ],
                "properties": {
                  "review": {
                    "type": "string"
                  },
                  "decision": {
                    "type": "string",
                    "enum": [
                      "restore",
                      "uphold"
                    ]
                  },
                  "note": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The decision was recorded: `{ok, hash}` names the chain entry.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The request could not be read: a JSON body naming `review` and `decision` is required.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "The credential is missing, or the door did not recognise it.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "This key may not do that: it is granted a different app, or the door named no account to scope the request to.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "No review with that id belongs to this account.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "The store refused the decision: the principal that removed this review cannot decide its appeal, or the review is not removed and has no removal to decide.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests: this key has spent its request ceiling, or this account has used its write allowance for the hour.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "This app failed while answering",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "A service this app needs did not answer, so the request could not be checked.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/_/api/v1/invitations": {
      "post": {
        "operationId": "postInvitations",
        "summary": "Create an invitation per eligible purchase and, when a sender is configured, send it. One purchase buys one review, and the address is never stored",
        "tags": [
          "campaign"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "business",
                  "recipients"
                ],
                "properties": {
                  "business": {
                    "type": "string"
                  },
                  "recipients": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "required": [
                        "purchase",
                        "contact"
                      ],
                      "properties": {
                        "purchase": {
                          "type": "string"
                        },
                        "contact": {
                          "type": "string"
                        }
                      }
                    }
                  },
                  "window_days": {
                    "type": "number"
                  },
                  "send": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "What the campaign produced — `{issued, planned, refused, sent, links}` — with the links in the answer whether or not a sender is configured, because the tokens exist in no other place.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The request could not be read: a JSON body naming `business` and between one and 200 recipients is required.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "The credential is missing, or the door did not recognise it.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "This key may not do that: it is granted a different app, or the door named no account to scope the request to.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "No business with that public id belongs to this account.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests: this key has spent its request ceiling, or this account has used its write allowance for the hour.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "This app failed while answering",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "A service this app needs did not answer, so the request could not be checked.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/_/api/v1/businesses": {
      "post": {
        "operationId": "postBusinesses",
        "summary": "Create a business under this account. Its public id is the URL, the claim record's label and the reply local part at once",
        "tags": [
          "business"
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "The caller's own retry handle. The same key sent twice writes one business and answers the business the first call answered. A header that is there and empty names nothing, so it is refused rather than read as a create.",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name",
                  "public_id",
                  "country"
                ],
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "public_id": {
                    "type": "string"
                  },
                  "country": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "That `Idempotency-Key` was already here: nothing was written, and the business is the one the first call answered with — even when this request's words moved.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "business",
                    "id"
                  ],
                  "properties": {
                    "business": {
                      "type": "string"
                    },
                    "id": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "201": {
            "description": "The business this call created, as `{business, id}`. `business` is the public id, which is the URL, the claim record's label and the reply local part at once.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "business",
                    "id"
                  ],
                  "properties": {
                    "business": {
                      "type": "string"
                    },
                    "id": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "The request could not be read",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "The credential is missing or does not open this account",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "This account may not do that",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Nothing is here",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "That public id is taken. It becomes the URL, the claim label and the reply address at once, so it is one name per business and the caller chooses another.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/_/api/v1/purchases": {
      "post": {
        "operationId": "postPurchases",
        "summary": "Record purchases against a business, hashing each address. A purchase is the proof a review rests on, so a duplicate reference is refused rather than counted twice",
        "tags": [
          "purchases"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "business",
                  "purchases"
                ],
                "properties": {
                  "business": {
                    "type": "string"
                  },
                  "purchases": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "required": [
                        "ref",
                        "amount_cents",
                        "currency",
                        "occurred_at",
                        "contact"
                      ],
                      "properties": {
                        "ref": {
                          "type": "string"
                        },
                        "amount_cents": {
                          "type": "integer"
                        },
                        "currency": {
                          "type": "string"
                        },
                        "occurred_at": {
                          "type": "integer"
                        },
                        "contact": {
                          "type": "string"
                        },
                        "proof_kind": {
                          "type": "string",
                          "enum": [
                            "receipt",
                            "invoice",
                            "order",
                            "none"
                          ]
                        },
                        "proof_ref": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "What the batch wrote — `{recorded, purchases, refused}` — one entry per row, so a partly refused batch names the rows that were refused and why.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The request could not be read: a JSON body naming `business` and between one and 500 purchases is required.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "The credential is missing, or the door did not recognise it.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "This key may not do that: it is granted a different app, or the door named no account to scope the request to.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "No business with that public id belongs to this account.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests: this key has spent its request ceiling, or this account has used its write allowance for the hour.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "This app failed while answering",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "A service this app needs did not answer, so the request could not be checked.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/_/api/v1/claims": {
      "post": {
        "operationId": "postClaims",
        "summary": "State the domain a business owns and get the record name and value that prove it, or the page tag instead",
        "tags": [
          "claim"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "business",
                  "domain"
                ],
                "properties": {
                  "business": {
                    "type": "string"
                  },
                  "domain": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The challenge to publish — `{business, domain, already_claimed, dns, page, note}` — with the record that wins when both proofs exist.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The request could not be read: a JSON body naming `business` and a domain is required, and the domain is given alone, without a scheme or a path.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "The credential is missing, or the door did not recognise it.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "This key may not do that: it is granted a different app, or the door named no account to scope the request to.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "No business with that public id belongs to this account.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests: this key has spent its request ceiling, or this account has used its write allowance for the hour.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "This app failed while answering",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "A service this app needs did not answer, so the request could not be checked.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/_/api/v1/claims/verify": {
      "post": {
        "operationId": "postClaimsVerify",
        "summary": "Read the TXT record and the page, and mark the business claimed when either answers. Until then it can publish nothing",
        "tags": [
          "claim"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "business"
                ],
                "properties": {
                  "business": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Claimed: `{claimed, method, reason, domain}` names which proof answered.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The request could not be read: a JSON body naming `business` is required, and the business states a domain before it can be verified.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "The credential is missing, or the door did not recognise it.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "This key may not do that: it is granted a different app, or the door named no account to scope the request to.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "No business with that public id belongs to this account.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "Not proved: neither the DNS TXT record nor the page tag answered, so the business is not claimed and can publish nothing yet.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests: this key has spent its request ceiling, or this account has used its write allowance for the hour.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "This app failed while answering",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "A service this app needs did not answer, so the request could not be checked.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "An API key minted on the account's settings page at zpe.vc/home/settings. Send it as `Authorization: Bearer <key>`."
      }
    },
    "schemas": {
      "Problem": {
        "type": "object",
        "description": "RFC 9457 problem+json: `type`, `title`, `status`, `code` and `instance`, plus `detail` when a person should read a sentence.",
        "required": [
          "type",
          "title",
          "status",
          "code",
          "instance"
        ],
        "properties": {
          "type": {
            "type": "string",
            "format": "uri"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer"
          },
          "code": {
            "type": "string",
            "enum": [
              "bad-request",
              "unauthenticated",
              "malformed",
              "unknown",
              "mismatch",
              "revoked",
              "expired",
              "another-account",
              "scope-refused",
              "grant-refused",
              "forbidden",
              "not-found",
              "method-not-allowed",
              "conflict",
              "gone",
              "payload-too-large",
              "unsupported-media-type",
              "unprocessable",
              "rate-limited",
              "payment-required",
              "not-open",
              "internal",
              "unavailable"
            ]
          },
          "instance": {
            "type": "string"
          },
          "detail": {
            "type": "string"
          }
        }
      }
    }
  },
  "x-surface": {
    "app": "zpe-reviews",
    "base": "/_/api/v1",
    "document": "/_/api/v1/openapi.json",
    "generated_by": "zpe-kit machineDocument"
  },
  "x-zpe-routes": 10,
  "x-zpe-documented": 10,
  "x-zpe-internal": []
}
