{
  "openapi": "3.1.0",
  "info": {
    "title": "URLert API",
    "version": "v1",
    "description": "The URLert API, version 1 (a beta). It checks a link, a message or a page before a program or an AI assistant acts on it, with the same checks as the website. There are six operations, each a POST with a JSON body, with a token made in Account, then AI agents, sent as `Authorization: Bearer <token>`. There is no operation that deletes a check or an account or changes how you sign in.\n\nA call is `POST /api/v1/<operation>`. A check answers at once with `status` `queued`: call `get_result` every few seconds with its `id` until `status` is `done` or `failed`. A check that fails is still a 200 answer; read `failure`. The limit is 20 checks a day for each account, across the API and the AI assistants' tools together; `get_result`, `get_guide` and `report_mistake` don't count, and the count starts again at 00:00 UTC. `RateLimit` and `RateLimit-Policy` headers describe the API's call rate, not the daily limit. Send an `Idempotency-Key` with a check or a report: a repeat of the same call gives back the first answer and doesn't count again. This is a beta: a change that would break a program gets a version 2, and version 1 is retired with a date announced in advance.\n\nEvery failure is `application/problem+json` with `status`, `code`, `detail` (words for a person) and `errors` (the fields at fault). Branch on `code`. A 400 `bad_request` means fix the request. A 400 `invalid_text` means send the message's text. A 401 `invalid_token` means make a new token. A 403 `insufficient_scope` means the token isn't allowed this operation. A 404 `not_found` says \"No check has this id. Checks are deleted after 30 days.\" and means stop polling. A 409 `no_result_yet` says \"This check has no result to report yet\" and means wait until the check is done. A 429 `daily_limit` says \"This account has made 20 checks today. The limit is 20 a day. The count starts again at 00:00 UTC.\" and a 429 `checks_paused` says \"Checks from assistants and programs are paused until 00:00 UTC. The website still works for people.\"; both send `Retry-After`, the seconds until 00:00 UTC, so wait that long and don't spread the calls over more accounts. A 429 `rate_limited` also sends `Retry-After`: slow down. A 500 or 503 is ours: retry with backoff, and the checks are safe to retry with an `Idempotency-Key`."
  },
  "servers": [
    {
      "url": "https://www.urlert.com/api/v1"
    }
  ],
  "paths": {
    "/check_link": {
      "post": {
        "operationId": "check_link",
        "summary": "Checks one link before you open it or act on it. Answers at once with the check's `id` and status `queued`: call get_result with the id until its status is `done` or `failed`. Counts as one of the account's 20 checks a day. Can answer 400 `bad_request` (the link isn't one web link, or `country` isn't two capital letters), 429 `daily_limit` or 429 `checks_paused`.",
        "security": [
          {
            "token": []
          }
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 255
            },
            "description": "A retry with the same key and body gets the first answer, for 24 hours"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "link"
                ],
                "additionalProperties": false,
                "properties": {
                  "link": {
                    "type": "string"
                  },
                  "action": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "default": null
                  },
                  "task": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "default": null
                  },
                  "country": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "default": null
                  }
                }
              },
              "example": {
                "link": "link",
                "action": "action",
                "task": "task",
                "country": "country"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The answer",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AgentResultV1"
                },
                "example": {
                  "id": "id",
                  "status": "queued",
                  "outcome": "malicious",
                  "outcome_name": "outcome_name",
                  "asks_for": [
                    "asks_for"
                  ],
                  "reasons": [
                    {
                      "text": "text"
                    }
                  ],
                  "sites": [
                    {
                      "host": "host",
                      "domain": "domain",
                      "age_days": 3,
                      "age_note": "age_note",
                      "anyone_can_publish": true,
                      "scam_lists": [
                        "scam_lists"
                      ]
                    }
                  ],
                  "opened_link": "opened_link",
                  "final_link": "final_link",
                  "views": [
                    {
                      "device": "device",
                      "state": "state"
                    }
                  ],
                  "reused": true,
                  "checked_at": "2030-01-15T09:30:00.000Z",
                  "expires_at": "2030-01-15T09:30:00.000Z",
                  "failure": "failure",
                  "message": "message",
                  "shared_copy": true,
                  "result_url": "result_url"
                }
              }
            }
          },
          "400": {
            "description": "bad request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "conflict",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "too many requests; `code` may be `checks_paused`, `daily_limit`",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal server error",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "service unavailable",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/check_message": {
      "post": {
        "operationId": "check_message",
        "summary": "Checks the text of a message, and the links in it. Answers at once with the check's `id`: call get_result until its status is `done` or `failed`. Counts as one of the account's 20 checks a day. Can answer 400 `bad_request` (the message is over 5,000 characters, the sender over 200, or `country` isn't two capital letters), 400 `invalid_text` (send the message's text), 429 `daily_limit` or 429 `checks_paused`.",
        "security": [
          {
            "token": []
          }
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 255
            },
            "description": "A retry with the same key and body gets the first answer, for 24 hours"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "text"
                ],
                "additionalProperties": false,
                "properties": {
                  "text": {
                    "type": "string"
                  },
                  "sender": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "default": null
                  },
                  "source": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "default": null
                  },
                  "action": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "default": null
                  },
                  "task": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "default": null
                  },
                  "country": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "default": null
                  }
                }
              },
              "example": {
                "text": "text",
                "sender": "sender",
                "source": "source",
                "action": "action",
                "task": "task",
                "country": "country"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The answer",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AgentResultV1"
                },
                "example": {
                  "id": "id",
                  "status": "queued",
                  "outcome": "malicious",
                  "outcome_name": "outcome_name",
                  "asks_for": [
                    "asks_for"
                  ],
                  "reasons": [
                    {
                      "text": "text"
                    }
                  ],
                  "sites": [
                    {
                      "host": "host",
                      "domain": "domain",
                      "age_days": 3,
                      "age_note": "age_note",
                      "anyone_can_publish": true,
                      "scam_lists": [
                        "scam_lists"
                      ]
                    }
                  ],
                  "opened_link": "opened_link",
                  "final_link": "final_link",
                  "views": [
                    {
                      "device": "device",
                      "state": "state"
                    }
                  ],
                  "reused": true,
                  "checked_at": "2030-01-15T09:30:00.000Z",
                  "expires_at": "2030-01-15T09:30:00.000Z",
                  "failure": "failure",
                  "message": "message",
                  "shared_copy": true,
                  "result_url": "result_url"
                }
              }
            }
          },
          "400": {
            "description": "bad request; `code` may be `invalid_text`",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "conflict",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "too many requests; `code` may be `checks_paused`, `daily_limit`",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal server error",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "service unavailable",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/check_page": {
      "post": {
        "operationId": "check_page",
        "summary": "Checks a page from your own view of it, which we don't open. The views say `not_opened`. Counts as one of the account's 20 checks a day. Can answer 400 `bad_request` (the link isn't one web link, or `page_text` is empty or over 20,000 characters), 429 `daily_limit` or 429 `checks_paused`.",
        "security": [
          {
            "token": []
          }
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 255
            },
            "description": "A retry with the same key and body gets the first answer, for 24 hours"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "link",
                  "page_text"
                ],
                "additionalProperties": false,
                "properties": {
                  "link": {
                    "type": "string"
                  },
                  "page_text": {
                    "type": "string"
                  },
                  "action": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "default": null
                  },
                  "task": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "default": null
                  }
                }
              },
              "example": {
                "link": "link",
                "page_text": "page_text",
                "action": "action",
                "task": "task"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The answer",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AgentResultV1"
                },
                "example": {
                  "id": "id",
                  "status": "queued",
                  "outcome": "malicious",
                  "outcome_name": "outcome_name",
                  "asks_for": [
                    "asks_for"
                  ],
                  "reasons": [
                    {
                      "text": "text"
                    }
                  ],
                  "sites": [
                    {
                      "host": "host",
                      "domain": "domain",
                      "age_days": 3,
                      "age_note": "age_note",
                      "anyone_can_publish": true,
                      "scam_lists": [
                        "scam_lists"
                      ]
                    }
                  ],
                  "opened_link": "opened_link",
                  "final_link": "final_link",
                  "views": [
                    {
                      "device": "device",
                      "state": "state"
                    }
                  ],
                  "reused": true,
                  "checked_at": "2030-01-15T09:30:00.000Z",
                  "expires_at": "2030-01-15T09:30:00.000Z",
                  "failure": "failure",
                  "message": "message",
                  "shared_copy": true,
                  "result_url": "result_url"
                }
              }
            }
          },
          "400": {
            "description": "bad request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "conflict",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "too many requests; `code` may be `checks_paused`, `daily_limit`",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal server error",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "service unavailable",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/get_result": {
      "post": {
        "operationId": "get_result",
        "summary": "A check's result by its id. Does not count against the day's 20 checks. Answers 404 `not_found` for an id nobody has, or one whose 30 days are over.",
        "security": [
          {
            "token": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "id"
                ],
                "additionalProperties": false,
                "properties": {
                  "id": {
                    "type": "string"
                  }
                }
              },
              "example": {
                "id": "id"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The answer",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AgentResultV1"
                },
                "example": {
                  "id": "id",
                  "status": "queued",
                  "outcome": "malicious",
                  "outcome_name": "outcome_name",
                  "asks_for": [
                    "asks_for"
                  ],
                  "reasons": [
                    {
                      "text": "text"
                    }
                  ],
                  "sites": [
                    {
                      "host": "host",
                      "domain": "domain",
                      "age_days": 3,
                      "age_note": "age_note",
                      "anyone_can_publish": true,
                      "scam_lists": [
                        "scam_lists"
                      ]
                    }
                  ],
                  "opened_link": "opened_link",
                  "final_link": "final_link",
                  "views": [
                    {
                      "device": "device",
                      "state": "state"
                    }
                  ],
                  "reused": true,
                  "checked_at": "2030-01-15T09:30:00.000Z",
                  "expires_at": "2030-01-15T09:30:00.000Z",
                  "failure": "failure",
                  "message": "message",
                  "shared_copy": true,
                  "result_url": "result_url"
                }
              }
            }
          },
          "400": {
            "description": "bad request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal server error",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "service unavailable",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/get_guide": {
      "post": {
        "operationId": "get_guide",
        "summary": "The steps for someone who already acted, most urgent first, or one scam guide. Does not count against the day's 20 checks.",
        "security": [
          {
            "token": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [],
                "additionalProperties": false,
                "properties": {
                  "did": {
                    "type": "array",
                    "items": {
                      "$ref": "#/components/schemas/GuideKey"
                    }
                  },
                  "scam": {
                    "default": null,
                    "anyOf": [
                      {
                        "$ref": "#/components/schemas/ScamKey"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                }
              },
              "example": {
                "did": [
                  "money"
                ],
                "scam": "how-scams-pretend"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The answer",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GuideV1"
                },
                "example": {
                  "title": "title",
                  "steps": [
                    {
                      "head": "head",
                      "body": "body",
                      "link": "link"
                    }
                  ],
                  "good_to_know": [
                    {
                      "head": "head",
                      "body": "body",
                      "link": "link"
                    }
                  ],
                  "guides": [
                    {
                      "key": "key",
                      "title": "title"
                    }
                  ],
                  "scam": {
                    "key": "key",
                    "title": "title",
                    "summary": "summary",
                    "examples": [
                      "examples"
                    ],
                    "signs": [
                      {
                        "head": "head",
                        "body": "body",
                        "link": "link"
                      }
                    ],
                    "steps": [
                      {
                        "head": "head",
                        "body": "body",
                        "link": "link"
                      }
                    ],
                    "link": "link"
                  },
                  "scams": [
                    {
                      "key": "key",
                      "title": "title"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "bad request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal server error",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "service unavailable",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/report_mistake": {
      "post": {
        "operationId": "report_mistake",
        "summary": "Tells us a result is wrong. One report for each check from each account: a second answers 200 with the first one's `sent_at`. Does not count against the day's 20 checks. Can answer 404 `not_found`, or 409 `no_result_yet` while the check has no result.",
        "security": [
          {
            "token": []
          }
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 255
            },
            "description": "A retry with the same key and body gets the first answer, for 24 hours"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "id",
                  "choice"
                ],
                "additionalProperties": false,
                "properties": {
                  "id": {
                    "type": "string"
                  },
                  "choice": {
                    "$ref": "#/components/schemas/ReportChoice"
                  },
                  "details": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "minLength": 1,
                    "maxLength": 1000,
                    "default": null
                  }
                }
              },
              "example": {
                "id": "id",
                "choice": "missed",
                "details": "details"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The answer",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MistakeReportV1"
                },
                "example": {
                  "id": "id",
                  "sent_at": "2030-01-15T09:30:00.000Z"
                }
              }
            }
          },
          "400": {
            "description": "bad request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "conflict; `code` may be `no_result_yet`",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "too many requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "internal server error",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "service unavailable",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "token": {
        "type": "http",
        "scheme": "bearer",
        "description": "An API token from the app's agents page"
      }
    },
    "schemas": {
      "AgentOutcome": {
        "type": "string",
        "enum": [
          "malicious",
          "scam",
          "risky",
          "suspicious",
          "nothing_found",
          "cant_tell"
        ],
        "description": "What we found. A closed list: a new value would be a new version of the API, so a program can branch on every one of them. `malicious` and `scam` are the two strongest findings, `risky` and `suspicious` ask for care, `nothing_found` means nothing wrong was found (not a promise that the message or page is safe), and `cant_tell` means we could not tell and need more to go on."
      },
      "AgentResultV1": {
        "type": "object",
        "required": [
          "id",
          "status",
          "outcome",
          "outcome_name",
          "asks_for",
          "reasons",
          "sites",
          "opened_link",
          "final_link",
          "views",
          "reused",
          "checked_at",
          "expires_at",
          "failure",
          "message",
          "shared_copy",
          "result_url"
        ],
        "description": "A check, as the API answers for it. Every field is always there: null or an empty list when it has nothing to say. Times are ISO 8601, in UTC.",
        "properties": {
          "id": {
            "type": "string",
            "description": "The check's id, for `get_result` and `report_mistake`. It works for 30 days."
          },
          "status": {
            "$ref": "#/components/schemas/CheckStatus",
            "description": "`queued`, `running`, `done` or `failed`; a closed list. Call `get_result` until it is `done` or `failed`. A check that ends `failed` is still a 200 answer: read `failure`."
          },
          "outcome": {
            "description": "Null until the check is done, and then one of `malicious`, `scam`, `risky`, `suspicious`, `nothing_found` and `cant_tell` (a closed list).",
            "anyOf": [
              {
                "$ref": "#/components/schemas/AgentOutcome"
              },
              {
                "type": "null"
              }
            ]
          },
          "outcome_name": {
            "type": [
              "string",
              "null"
            ],
            "description": "The outcome in words, for showing to a person. Never branch on it. Null when `outcome` is."
          },
          "asks_for": {
            "type": "array",
            "description": "What the message or page asks the person for, from `money`, `account`, `device`, `data`, `attention` and `agents` (instructions hidden for AI assistants). An open list. Empty when it asks for nothing or the check is not done.",
            "items": {
              "type": "string"
            }
          },
          "reasons": {
            "type": "array",
            "description": "The sentences under \"Why\" on the check's result page, in the same order and words, at most four (for a shared copy, as the shared page says them). Empty until the check is done.",
            "items": {
              "$ref": "#/components/schemas/ReasonV1"
            }
          },
          "sites": {
            "type": "array",
            "description": "The sites the check looked at.",
            "items": {
              "$ref": "#/components/schemas/SiteV1"
            }
          },
          "opened_link": {
            "type": [
              "string",
              "null"
            ],
            "description": "The link we opened. Null when nothing was opened; when `shared_copy` is true it shows only the site."
          },
          "final_link": {
            "type": [
              "string",
              "null"
            ],
            "description": "The address the opened page ended on after redirects. Null when nothing was opened, and when `shared_copy` is true."
          },
          "views": {
            "type": "array",
            "description": "How our phone and computer views of the link came out.",
            "items": {
              "$ref": "#/components/schemas/ViewV1"
            }
          },
          "reused": {
            "type": "boolean",
            "description": "True when this answer is the result of an identical recent check and not a new look."
          },
          "checked_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the result was found (the earlier check's time when `reused`). Null until the check is done."
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the check is deleted, after which `get_result` answers 404."
          },
          "failure": {
            "type": [
              "string",
              "null"
            ],
            "description": "Null unless the check failed, and then why: `unavailable` (try again in a few minutes), `our_limit` (we reached our own limit for the day: try after 00:00 UTC) or `too_long`. An open list."
          },
          "message": {
            "type": [
              "string",
              "null"
            ],
            "description": "One plain sentence about the state, for a person, or null when there is nothing to add."
          },
          "shared_copy": {
            "type": "boolean",
            "description": "True when the account asking did not make this check, so addresses are cut to their site."
          },
          "result_url": {
            "type": "string",
            "description": "The page a person can open for this check. Anyone with the link sees the shared copy."
          }
        }
      },
      "CheckStatus": {
        "type": "string",
        "enum": [
          "queued",
          "running",
          "done",
          "failed"
        ],
        "description": "Where a check is: `queued`, `running`, `done` or `failed`. A closed list."
      },
      "GuideKey": {
        "type": "string",
        "enum": [
          "money",
          "card",
          "installed",
          "remote",
          "password",
          "id",
          "replied",
          "assistant",
          "opened"
        ],
        "description": "What the person did: one of the nine \"What did you do?\" guides, `money`, `card`, `installed`, `remote`, `password`, `id`, `replied`, `assistant` or `opened`. A closed list."
      },
      "GuideV1": {
        "type": "object",
        "required": [
          "title",
          "steps",
          "good_to_know",
          "guides",
          "scam",
          "scams"
        ],
        "description": "The help for someone who already acted, and the scam guides.",
        "properties": {
          "title": {
            "type": "string",
            "description": "What the person did, in one line."
          },
          "steps": {
            "type": "array",
            "description": "What to do, most urgent first. Empty when `did` was empty.",
            "items": {
              "$ref": "#/components/schemas/StepV1"
            }
          },
          "good_to_know": {
            "type": "array",
            "description": "What is useful after.",
            "items": {
              "$ref": "#/components/schemas/StepV1"
            }
          },
          "guides": {
            "type": "array",
            "description": "Every kind of \"what did you do\" guide, so a program can ask again for more.",
            "items": {
              "$ref": "#/components/schemas/KeyTitleV1"
            }
          },
          "scam": {
            "description": "One scam guide when `scam` was asked for, otherwise null.",
            "anyOf": [
              {
                "$ref": "#/components/schemas/ScamV1"
              },
              {
                "type": "null"
              }
            ]
          },
          "scams": {
            "type": "array",
            "description": "Every scam guide's key and title.",
            "items": {
              "$ref": "#/components/schemas/KeyTitleV1"
            }
          }
        }
      },
      "KeyTitleV1": {
        "type": "object",
        "required": [
          "key",
          "title"
        ],
        "description": "A guide's key and its title.",
        "properties": {
          "key": {
            "type": "string",
            "description": "The guide's key. An open list: a new guide can be added in version 1, so don't treat the keys as fixed."
          },
          "title": {
            "type": "string",
            "description": "The guide's title."
          }
        }
      },
      "MistakeReportV1": {
        "type": "object",
        "required": [
          "id",
          "sent_at"
        ],
        "description": "What a report that a result is wrong answers.",
        "properties": {
          "id": {
            "type": "string",
            "description": "The check's id."
          },
          "sent_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the report was sent (an ISO 8601 time in UTC). A second report for the same check from the same account answers the same, with the first report's time."
          }
        }
      },
      "ReasonV1": {
        "type": "object",
        "required": [
          "text"
        ],
        "description": "One reason for the outcome.",
        "properties": {
          "text": {
            "type": "string",
            "description": "One sentence for a person, a line of the Why on the check's result page. It quotes the message or the page in curly quotes where that helps."
          }
        }
      },
      "ReportChoice": {
        "type": "string",
        "enum": [
          "missed",
          "false_alarm",
          "other"
        ],
        "description": "What is wrong with the result: `missed` (it's a scam, but we said it wasn't), `false_alarm` (it's real, but we said it's a scam) or `other`. A closed list."
      },
      "ScamKey": {
        "type": "string",
        "enum": [
          "how-scams-pretend",
          "parcel-toll-tax-fees",
          "bank-and-card-alerts",
          "safe-account-scams",
          "fake-invoices",
          "prizes-and-refunds",
          "jobs-and-paid-tasks",
          "fake-shops",
          "marketplace",
          "investments",
          "crypto-wallets",
          "threats-and-blackmail",
          "codes-and-sign-in-requests",
          "fake-sign-in-pages",
          "qr-codes",
          "fake-downloads",
          "fake-verify-human",
          "tech-support",
          "id-theft",
          "hi-mom-new-number",
          "online-romance",
          "call-or-reply",
          "ai-assistants"
        ],
        "description": "The key of a scam guide, which is also its address on the website (`/scams/<key>`). A closed list for now; `scams` in `get_guide` lists them all."
      },
      "ScamV1": {
        "type": "object",
        "required": [
          "key",
          "title",
          "summary",
          "examples",
          "signs",
          "steps",
          "link"
        ],
        "description": "One scam guide.",
        "properties": {
          "key": {
            "type": "string",
            "description": "The scam guide's key, which is also its address on the website (`/scams/<key>`)."
          },
          "title": {
            "type": "string",
            "description": "The guide's name."
          },
          "summary": {
            "type": "string",
            "description": "What the scam is."
          },
          "examples": {
            "type": "array",
            "description": "Messages that look like it.",
            "items": {
              "type": "string"
            }
          },
          "signs": {
            "type": "array",
            "description": "How to spot one.",
            "items": {
              "$ref": "#/components/schemas/StepV1"
            }
          },
          "steps": {
            "type": "array",
            "description": "What to do, with the US reporting line where the guide reports.",
            "items": {
              "$ref": "#/components/schemas/StepV1"
            }
          },
          "link": {
            "type": "string",
            "description": "The guide's full address on the website."
          }
        }
      },
      "SiteV1": {
        "type": "object",
        "required": [
          "host",
          "domain",
          "age_days",
          "age_note",
          "anyone_can_publish",
          "scam_lists"
        ],
        "description": "A site the check looked at.",
        "properties": {
          "host": {
            "type": "string",
            "description": "The host as it appeared."
          },
          "domain": {
            "type": "string",
            "description": "The name registered for the host."
          },
          "age_days": {
            "type": [
              "integer",
              "null"
            ],
            "description": "The days since the domain was registered, or null when we have no age; then `age_note` says why."
          },
          "age_note": {
            "type": [
              "string",
              "null"
            ],
            "description": "Why `age_days` is null: `ip_address` (the address is an IP address), `unregistered`, `lookup_failed`, `not_checked` or `no_date` (the registry has no date). Null when `age_days` is set. An open list: a value you don't know means a reason we haven't documented."
          },
          "anyone_can_publish": {
            "type": "boolean",
            "description": "True when the site is a service where anyone can put up a page, so the site's name says little about who made the page."
          },
          "scam_lists": {
            "type": [
              "array",
              "null"
            ],
            "description": "The names of the lists of known scam sites this site is on. An empty list when it was checked and is on none. Null when it was not checked against lists: no list could be read when the check ran, or the check is from before we kept this.",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "StepV1": {
        "type": "object",
        "required": [
          "head",
          "body",
          "link"
        ],
        "description": "One step of a guide.",
        "properties": {
          "head": {
            "type": "string",
            "description": "The step's first line."
          },
          "body": {
            "type": "string",
            "description": "What to do."
          },
          "link": {
            "type": [
              "string",
              "null"
            ],
            "description": "An address to open for this step, or null."
          }
        }
      },
      "ViewV1": {
        "type": "object",
        "required": [
          "device",
          "state"
        ],
        "description": "How one view of the link came out.",
        "properties": {
          "device": {
            "type": "string",
            "description": "`phone` or `computer`."
          },
          "state": {
            "type": "string",
            "description": "What we saw or why we saw nothing: `picture` (we opened it), `blank`, `human_check` (a check that asks for proof of being human was in the way), `provider_warning` (the hosting company had already blocked the page), `refused` (the site refused to show us the page), `unsupported` (we can't open pages on this site), `gone`, `file` (the link is a file, not a page), `failed` (we couldn't open it this time), `no_response`, `cut_off` (the link was cut off, so we don't have the whole address), `slow`, `no_dns` (the address doesn't exist), `cert` (the site's security certificate is broken), `site_error`, `not_opened` (we didn't open it: for example you sent your own view of the page), `daily_limit` (the account's share of opened pages for the day is used: try tomorrow) and `our_limit` (we reached our own limit or capacity for opening pages). An open list: a value you don't know means a reason we haven't documented."
          }
        }
      },
      "Problem": {
        "type": "object",
        "required": [
          "type",
          "status",
          "code",
          "detail",
          "errors"
        ],
        "properties": {
          "type": {
            "type": "string",
            "format": "uri"
          },
          "status": {
            "type": "integer"
          },
          "code": {
            "type": "string"
          },
          "detail": {
            "type": "string"
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "field",
                "detail"
              ],
              "properties": {
                "field": {
                  "type": "string"
                },
                "detail": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    }
  }
}