{
  "openapi": "3.1.0",
  "info": {
    "title": "HashScraper API v5",
    "version": "5.0.0-beta",
    "description": "HashScraper API v5 (beta). Main differences from v4:\n1. Resources are renamed: schedules are bots, schedule results are datasets, and a bot can have several schedules called plans (`/v5/api/plans/...`).\n2. Retry-safe writes: starting collections (bot, plan, bulk), retrying a dataset and creating a plan require an `Idempotency-Key` header; a retry with the same key returns the first response with `Idempotent-Replayed: true` and never collects twice.\n3. One response envelope everywhere (`result`, `version`, `request_id`, `elapsed_sec`, `data`; errors add `code`, `message`, `details`) with cursor pages (`count`, `next_cursor`) and fixed fields (missing values are `null`, not omitted).\nAuthenticate with `Authorization: Bearer <api_key>` (the same key as v4).",
    "contact": {
      "name": "HashScraper",
      "url": "https://www.hashscraper.com"
    }
  },
  "servers": [
    {
      "url": "https://www.hashscraper.com",
      "description": "Production"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "System",
      "description": "Health check and the account behind the key"
    },
    {
      "name": "Bots",
      "description": "My bots"
    },
    {
      "name": "Bot settings",
      "description": "Manual collection settings and Excel input file"
    },
    {
      "name": "Notifications",
      "description": "Webhook"
    },
    {
      "name": "Plans",
      "description": "Schedules of a bot (called plans in v5)"
    },
    {
      "name": "Collections",
      "description": "Start, run, retry and cancel collections"
    },
    {
      "name": "Datasets",
      "description": "Collected datasets and rows"
    }
  ],
  "paths": {
    "/v5/api/bots": {
      "get": {
        "operationId": "listBots",
        "tags": [
          "Bots"
        ],
        "summary": "List my bots",
        "parameters": [
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Limit"
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/SuccessEnvelope"
                    },
                    {
                      "$ref": "#/components/schemas/PageInfo"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Bot"
                          }
                        }
                      },
                      "required": [
                        "data"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v5/api/bots/{bot_id}": {
      "get": {
        "operationId": "getBot",
        "tags": [
          "Bots"
        ],
        "summary": "Bot detail",
        "parameters": [
          {
            "$ref": "#/components/parameters/BotId"
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/SuccessEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/BotDetail"
                        }
                      },
                      "required": [
                        "data"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v5/api/bots/{bot_id}/collections": {
      "post": {
        "operationId": "startCollection",
        "tags": [
          "Collections"
        ],
        "summary": "Start a collection",
        "description": "Requires the `Idempotency-Key` header. Retrying with the same key and the same request returns the first response again with `Idempotent-Replayed: true`; the same key with a different request is `IDEMPOTENCY_KEY_REUSED`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BotId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CollectionRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/SuccessEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/CollectionResult"
                        }
                      },
                      "required": [
                        "data"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v5/api/bots/{bot_id}/inputs": {
      "get": {
        "operationId": "getBotInputs",
        "tags": [
          "Bots"
        ],
        "summary": "Input definitions of a bot",
        "parameters": [
          {
            "$ref": "#/components/parameters/BotId"
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/SuccessEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/BotInputs"
                        }
                      },
                      "required": [
                        "data"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v5/api/bots/{bot_id}/notifications": {
      "get": {
        "operationId": "getBotNotifications",
        "tags": [
          "Notifications"
        ],
        "summary": "Webhook settings and last delivery",
        "parameters": [
          {
            "$ref": "#/components/parameters/BotId"
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/SuccessEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/Notifications"
                        }
                      },
                      "required": [
                        "data"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "put": {
        "operationId": "updateBotNotifications",
        "tags": [
          "Notifications"
        ],
        "summary": "Set or remove the webhook URL",
        "parameters": [
          {
            "$ref": "#/components/parameters/BotId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NotificationsUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/SuccessEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/Notifications"
                        }
                      },
                      "required": [
                        "data"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v5/api/bots/{bot_id}/notifications/test": {
      "post": {
        "operationId": "testBotWebhook",
        "tags": [
          "Notifications"
        ],
        "summary": "Send a test webhook",
        "parameters": [
          {
            "$ref": "#/components/parameters/BotId"
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/SuccessEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/WebhookTestResult"
                        }
                      },
                      "required": [
                        "data"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v5/api/bots/{bot_id}/plans": {
      "get": {
        "operationId": "listPlans",
        "tags": [
          "Plans"
        ],
        "summary": "Plans of a bot",
        "parameters": [
          {
            "$ref": "#/components/parameters/BotId"
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/SuccessEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "count": {
                          "type": "integer"
                        }
                      },
                      "required": [
                        "count"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/PlanList"
                        }
                      },
                      "required": [
                        "data"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "post": {
        "operationId": "createPlan",
        "tags": [
          "Plans"
        ],
        "summary": "Create a plan",
        "description": "Requires the `Idempotency-Key` header. Retrying with the same key and the same request returns the first response again with `Idempotent-Replayed: true`; the same key with a different request is `IDEMPOTENCY_KEY_REUSED`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BotId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PlanCreateRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/SuccessEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/Plan"
                        }
                      },
                      "required": [
                        "data"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v5/api/bots/{bot_id}/settings": {
      "get": {
        "operationId": "getBotSettings",
        "tags": [
          "Bot settings"
        ],
        "summary": "Manual collection settings",
        "parameters": [
          {
            "$ref": "#/components/parameters/BotId"
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/SuccessEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/BotSettings"
                        }
                      },
                      "required": [
                        "data"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "patch": {
        "operationId": "updateBotSettings",
        "tags": [
          "Bot settings"
        ],
        "summary": "Change manual collection settings",
        "parameters": [
          {
            "$ref": "#/components/parameters/BotId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BotSettingsUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/SuccessEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/BotSettings"
                        }
                      },
                      "required": [
                        "data"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v5/api/bots/{bot_id}/settings/excel": {
      "put": {
        "operationId": "uploadBotExcel",
        "tags": [
          "Bot settings"
        ],
        "summary": "Upload the Excel input file",
        "description": "Multipart upload (field `file`). Replaces the active file. Collecting with Excel input itself is not supported in v5 yet.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BotId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/ExcelUploadRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/SuccessEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/ExcelUploadResult"
                        }
                      },
                      "required": [
                        "data"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v5/api/collections/bulk": {
      "post": {
        "operationId": "startBulkCollection",
        "tags": [
          "Collections"
        ],
        "summary": "Start collections for up to 100 bots",
        "description": "Requires the `Idempotency-Key` header. Retrying with the same key and the same request returns the first response again with `Idempotent-Replayed: true`; the same key with a different request is `IDEMPOTENCY_KEY_REUSED`. Each item is handled on its own; the top-level `result` is `success`, `partial_success` or `failure`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BulkRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/SuccessEnvelope"
                    },
                    {
                      "$ref": "#/components/schemas/BulkExtra"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/BulkResult"
                        }
                      },
                      "required": [
                        "data"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v5/api/collections/bulk_jobs": {
      "post": {
        "operationId": "createBulkJob",
        "tags": [
          "Collections"
        ],
        "summary": "Accept up to 5,000 collections and process them in the background",
        "description": "Requires the `Idempotency-Key` header. Retrying with the same key and the same request returns the first response again with `Idempotent-Replayed: true`; the same key with a different request is `IDEMPOTENCY_KEY_REUSED`. Returns `202` with a job id right away; nothing is collected yet. Each item is then processed like bulk collection (same checks, same credits). Poll the job to read the results.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BulkJobRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/SuccessEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/BulkJobAccepted"
                        }
                      },
                      "required": [
                        "data"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v5/api/collections/bulk_jobs/{job_id}": {
      "get": {
        "operationId": "getBulkJob",
        "tags": [
          "Collections"
        ],
        "summary": "Progress and item results of a bulk job",
        "parameters": [
          {
            "$ref": "#/components/parameters/BulkJobId"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Limit"
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/SuccessEnvelope"
                    },
                    {
                      "$ref": "#/components/schemas/PageInfo"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/BulkJobDetail"
                        }
                      },
                      "required": [
                        "data"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v5/api/datasets": {
      "get": {
        "operationId": "listDatasets",
        "tags": [
          "Datasets"
        ],
        "summary": "List my datasets (newest first)",
        "parameters": [
          {
            "name": "bot_id",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Only this bot."
          },
          {
            "name": "plan_id",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/PlanId"
            },
            "description": "Only datasets started by this plan."
          },
          {
            "name": "trigger",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/DatasetTrigger"
            }
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/DatasetStatus"
            }
          },
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Created at or after (ISO 8601 or date, KST)."
          },
          {
            "name": "to",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Created at or before (ISO 8601 or date, KST)."
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Limit"
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/SuccessEnvelope"
                    },
                    {
                      "$ref": "#/components/schemas/PageInfo"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Dataset"
                          }
                        }
                      },
                      "required": [
                        "data"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v5/api/datasets/{dataset_id}": {
      "get": {
        "operationId": "getDataset",
        "tags": [
          "Datasets"
        ],
        "summary": "Dataset detail",
        "parameters": [
          {
            "$ref": "#/components/parameters/DatasetId"
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/SuccessEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/DatasetDetail"
                        }
                      },
                      "required": [
                        "data"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v5/api/datasets/{dataset_id}/cancel": {
      "post": {
        "operationId": "cancelDataset",
        "tags": [
          "Collections"
        ],
        "summary": "Cancel a running collection",
        "description": "An ended dataset is left as it is and its current state is returned. `Idempotency-Key` is optional.",
        "parameters": [
          {
            "$ref": "#/components/parameters/DatasetId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKeyOptional"
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/SuccessEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/DatasetDetail"
                        }
                      },
                      "required": [
                        "data"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v5/api/datasets/{dataset_id}/results": {
      "get": {
        "operationId": "listDatasetResults",
        "tags": [
          "Datasets"
        ],
        "summary": "Collected rows of a dataset",
        "parameters": [
          {
            "$ref": "#/components/parameters/DatasetId"
          },
          {
            "name": "sorting",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ],
              "default": "asc"
            }
          },
          {
            "name": "since",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Only rows created at or after this time (ISO 8601, KST)."
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Limit"
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/SuccessEnvelope"
                    },
                    {
                      "$ref": "#/components/schemas/PageInfo"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/ResultRow"
                          }
                        }
                      },
                      "required": [
                        "data"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v5/api/datasets/{dataset_id}/retry": {
      "post": {
        "operationId": "retryDataset",
        "tags": [
          "Collections"
        ],
        "summary": "Collect an ended dataset again (same id)",
        "description": "Requires the `Idempotency-Key` header. Retrying with the same key and the same request returns the first response again with `Idempotent-Replayed: true`; the same key with a different request is `IDEMPOTENCY_KEY_REUSED`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/DatasetId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/SuccessEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/DatasetDetail"
                        }
                      },
                      "required": [
                        "data"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v5/api/health": {
      "get": {
        "operationId": "getHealth",
        "tags": [
          "System"
        ],
        "summary": "Health check",
        "description": "No API key needed. Not counted in API usage.",
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/SuccessEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/HealthData"
                        }
                      },
                      "required": [
                        "data"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": []
      }
    },
    "/v5/api/me": {
      "get": {
        "operationId": "getMe",
        "tags": [
          "System"
        ],
        "summary": "Who am I",
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/SuccessEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/MeData"
                        }
                      },
                      "required": [
                        "data"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v5/api/plans/{plan_id}": {
      "get": {
        "operationId": "getPlan",
        "tags": [
          "Plans"
        ],
        "summary": "Plan detail",
        "parameters": [
          {
            "$ref": "#/components/parameters/PlanIdPath"
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/SuccessEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/Plan"
                        }
                      },
                      "required": [
                        "data"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "patch": {
        "operationId": "updatePlan",
        "tags": [
          "Plans"
        ],
        "summary": "Change a plan (only the sent fields)",
        "parameters": [
          {
            "$ref": "#/components/parameters/PlanIdPath"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PlanUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/SuccessEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/Plan"
                        }
                      },
                      "required": [
                        "data"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "delete": {
        "operationId": "deletePlan",
        "tags": [
          "Plans"
        ],
        "summary": "Delete a plan",
        "description": "Plan 1 (computed, linked to bot settings, or first) cannot be deleted; turn it off with PATCH. Datasets stay.",
        "parameters": [
          {
            "$ref": "#/components/parameters/PlanIdPath"
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/SuccessEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/PlanDeleted"
                        }
                      },
                      "required": [
                        "data"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v5/api/plans/{plan_id}/copy_settings": {
      "post": {
        "operationId": "copyPlanSettings",
        "tags": [
          "Plans"
        ],
        "summary": "Copy bot settings into a plan",
        "parameters": [
          {
            "$ref": "#/components/parameters/PlanIdPath"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CopySettingsRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/SuccessEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/PlanCopyResult"
                        }
                      },
                      "required": [
                        "data"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v5/api/plans/{plan_id}/excel": {
      "put": {
        "operationId": "putPlanExcel",
        "tags": [
          "Plans"
        ],
        "summary": "Excel input for a plan (not supported yet)",
        "description": "Always answers `EXCEL_NOT_SUPPORTED_YET` (422) for an existing plan.",
        "parameters": [
          {
            "$ref": "#/components/parameters/PlanIdPath"
          }
        ],
        "responses": {
          "200": {
            "description": "Never returned yet.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/SuccessEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "object",
                          "properties": {},
                          "required": []
                        }
                      },
                      "required": [
                        "data"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v5/api/plans/{plan_id}/preview": {
      "post": {
        "operationId": "previewPlan",
        "tags": [
          "Plans"
        ],
        "summary": "Preview upcoming runs without saving",
        "parameters": [
          {
            "$ref": "#/components/parameters/PlanIdPath"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PlanPreviewRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/SuccessEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/PlanPreview"
                        }
                      },
                      "required": [
                        "data"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v5/api/plans/{plan_id}/run": {
      "post": {
        "operationId": "runPlanNow",
        "tags": [
          "Collections"
        ],
        "summary": "Run a plan once now",
        "description": "Requires the `Idempotency-Key` header. Retrying with the same key and the same request returns the first response again with `Idempotent-Replayed: true`; the same key with a different request is `IDEMPOTENCY_KEY_REUSED`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/PlanIdPath"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/SuccessEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/DatasetDetail"
                        }
                      },
                      "required": [
                        "data"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v5/api/plans/{plan_id}/runs": {
      "get": {
        "operationId": "listPlanRuns",
        "tags": [
          "Plans"
        ],
        "summary": "Scheduled runs and whether each one ran",
        "description": "`cursor` is the epoch seconds of the last scheduled time of the previous page (newest first).",
        "parameters": [
          {
            "$ref": "#/components/parameters/PlanIdPath"
          },
          {
            "name": "state",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "ran",
                "skipped",
                "missed",
                "upcoming"
              ]
            }
          },
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Scheduled at or after (ISO 8601 or YYYY-MM-DD). Default 14 days ago. Range at most 31 days."
          },
          {
            "name": "to",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Scheduled at or before (ISO 8601 or YYYY-MM-DD)."
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Limit"
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/SuccessEnvelope"
                    },
                    {
                      "$ref": "#/components/schemas/PageInfo"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/PlanRuns"
                        }
                      },
                      "required": [
                        "data"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Your API key, sent as `Authorization: Bearer <api_key>`."
      }
    },
    "headers": {
      "XRequestId": {
        "description": "Same as `request_id` in the body.",
        "schema": {
          "type": "string"
        }
      },
      "IdempotentReplayed": {
        "description": "`true` when this response is the stored first response of the same `Idempotency-Key`. Absent on the first response.",
        "schema": {
          "type": "string",
          "enum": [
            "true"
          ]
        }
      }
    },
    "parameters": {
      "BotId": {
        "name": "bot_id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "Bot public id (16 hex characters)."
      },
      "PlanIdPath": {
        "name": "plan_id",
        "in": "path",
        "required": true,
        "schema": {
          "$ref": "#/components/schemas/PlanId"
        },
        "description": "Plan id: a number, or `one-<bot id>` for a bot's computed \"Plan 1\"."
      },
      "BulkJobId": {
        "name": "job_id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "Job id returned when the job was accepted."
      },
      "DatasetId": {
        "name": "dataset_id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "integer"
        },
        "description": "Dataset id."
      },
      "Cursor": {
        "name": "cursor",
        "in": "query",
        "schema": {
          "type": "string"
        },
        "description": "`next_cursor` of the previous page."
      },
      "Limit": {
        "name": "limit",
        "in": "query",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 1000,
          "default": 100
        },
        "description": "Page size."
      },
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": true,
        "schema": {
          "type": "string",
          "minLength": 1,
          "maxLength": 255
        },
        "description": "Unique key (1-255 characters, for example a UUID) per request. Reuse it only to retry the same request. Missing key is `IDEMPOTENCY_KEY_REQUIRED`."
      },
      "IdempotencyKeyOptional": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": false,
        "schema": {
          "type": "string",
          "minLength": 1,
          "maxLength": 255
        },
        "description": "Optional here. When sent, the same retry rules apply."
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Missing or invalid parameter (`MISSING_PARAM`, `INVALID_PARAM`, `VALIDATION_FAILED`, `IDEMPOTENCY_KEY_REQUIRED`).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "API key missing or invalid (`MISSING_API_KEY`, `INVALID_API_KEY`).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            }
          }
        }
      },
      "PaymentRequired": {
        "description": "Service ticket expired or credits exhausted (`TICKET_EXPIRED`, `CREDIT_EXHAUSTED`).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            }
          }
        }
      },
      "Forbidden": {
        "description": "Not allowed (`FORBIDDEN`).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            }
          }
        }
      },
      "NotFound": {
        "description": "Bot, plan, dataset or bulk job not found, or not yours (`BOT_NOT_FOUND`, `PLAN_NOT_FOUND`, `DATASET_NOT_FOUND`, `BULK_JOB_NOT_FOUND`, `RESOURCE_NOT_FOUND`).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            }
          }
        }
      },
      "Conflict": {
        "description": "State conflict (`ALREADY_RUNNING`, `BOT_MAINTENANCE`, `EXECUTION_BLOCKED`, `PLAN_UNDELETABLE`, `PLAN_MODE_READONLY`, `REQUEST_IN_PROGRESS`).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            }
          }
        }
      },
      "UnprocessableEntity": {
        "description": "Request understood but refused (`IDEMPOTENCY_KEY_REUSED`, `PLAN_CONDITION_BLOCKED`, `PLAN_MODE_REFUSED`, `PLAN_NAME_TAKEN`, `EXCEL_NOT_SUPPORTED_YET`, `EXCEL_FILE_REQUIRED`, `EXCEL_FILE_UNREADABLE`, `WEBHOOK_NOT_SET`).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            }
          }
        }
      },
      "RateLimited": {
        "description": "Rate limit exceeded (`RATE_LIMITED`).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            }
          }
        }
      },
      "ServerError": {
        "description": "Server error (`INTERNAL_ERROR`).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            }
          }
        }
      }
    },
    "schemas": {
      "SuccessEnvelope": {
        "type": "object",
        "properties": {
          "result": {
            "type": "string",
            "enum": [
              "success",
              "partial_success",
              "failure"
            ],
            "description": "`success` for most responses. Only bulk collection can be `partial_success` or `failure`."
          },
          "version": {
            "const": "v5"
          },
          "request_id": {
            "type": "string",
            "description": "Request number. Send `X-Request-ID: req_<anything>` to have it echoed; otherwise the server makes `req_<uuid>`."
          },
          "elapsed_sec": {
            "type": "number",
            "description": "Seconds the server spent on the request."
          }
        },
        "required": [
          "result",
          "version",
          "request_id",
          "elapsed_sec"
        ],
        "description": "Common success envelope. The payload is in `data`."
      },
      "PageInfo": {
        "type": "object",
        "properties": {
          "count": {
            "type": "integer",
            "description": "Number of items in this page."
          },
          "next_cursor": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Pass as `cursor` to get the next page. `null` on the last page."
          }
        },
        "required": [
          "count",
          "next_cursor"
        ],
        "description": "Cursor pagination result. Request with `cursor` and `limit` (default 100, max 1000)."
      },
      "ErrorCode": {
        "type": "string",
        "enum": [
          "MISSING_API_KEY",
          "INVALID_API_KEY",
          "FORBIDDEN",
          "MISSING_PARAM",
          "INVALID_PARAM",
          "VALIDATION_FAILED",
          "RESOURCE_NOT_FOUND",
          "TICKET_EXPIRED",
          "CREDIT_EXHAUSTED",
          "EXECUTION_BLOCKED",
          "RATE_LIMITED",
          "INTERNAL_ERROR",
          "BOT_NOT_FOUND",
          "PLAN_NOT_FOUND",
          "DATASET_NOT_FOUND",
          "BULK_JOB_NOT_FOUND",
          "BOT_MAINTENANCE",
          "ALREADY_RUNNING",
          "IDEMPOTENCY_KEY_REQUIRED",
          "IDEMPOTENCY_KEY_REUSED",
          "REQUEST_IN_PROGRESS",
          "PLAN_CONDITION_BLOCKED",
          "PLAN_UNDELETABLE",
          "PLAN_MODE_REFUSED",
          "PLAN_MODE_READONLY",
          "PLAN_NAME_TAKEN",
          "EXCEL_NOT_SUPPORTED_YET",
          "EXCEL_FILE_REQUIRED",
          "EXCEL_FILE_UNREADABLE",
          "WEBHOOK_NOT_SET"
        ],
        "description": "Machine-readable error code. The HTTP status is fixed per code."
      },
      "ErrorEnvelope": {
        "type": "object",
        "properties": {
          "result": {
            "const": "error"
          },
          "version": {
            "const": "v5"
          },
          "request_id": {
            "type": "string"
          },
          "code": {
            "$ref": "#/components/schemas/ErrorCode"
          },
          "message": {
            "type": "string",
            "description": "Human-readable English message."
          },
          "elapsed_sec": {
            "type": "number"
          },
          "details": {
            "type": "object",
            "additionalProperties": true,
            "description": "Optional. Parameter name (`param_name`), allowed values (`allowed`), hints or validation errors (`errors`)."
          }
        },
        "required": [
          "result",
          "version",
          "request_id",
          "code",
          "message",
          "elapsed_sec"
        ],
        "description": "Common error envelope."
      },
      "PlanId": {
        "type": "string",
        "description": "Plan id as a string. A plan row is its number (\"12\"). A bot that has a period but no plan rows yet has a computed \"Plan 1\" with id `one-<bot id>` (for example `one-0123456789abcdef`).",
        "pattern": "^([1-9][0-9]*|one-[a-f0-9]{16})$",
        "examples": [
          "12",
          "one-0123456789abcdef"
        ]
      },
      "DatasetStatus": {
        "type": "string",
        "enum": [
          "done",
          "running",
          "attention",
          "waiting",
          "retrying",
          "failed",
          "canceling",
          "canceled"
        ]
      },
      "DatasetTrigger": {
        "type": "string",
        "enum": [
          "manual",
          "period",
          "period_manual",
          "api",
          "excel"
        ],
        "description": "How the dataset was started."
      },
      "ScheduleGroup": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "name_en": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "id",
          "name",
          "name_en"
        ]
      },
      "WorkerSource": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "version": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "updated_at": {
            "oneOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ]
          },
          "price": {
            "oneOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "name",
          "version",
          "updated_at",
          "price"
        ]
      },
      "ActivePlan": {
        "type": "object",
        "properties": {
          "id": {
            "$ref": "#/components/schemas/PlanId"
          },
          "name": {
            "type": "string"
          },
          "label": {
            "type": "string",
            "description": "Period sentence in Korean, for example \"10분마다\"."
          }
        },
        "required": [
          "id",
          "name",
          "label"
        ]
      },
      "LatestDataset": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "status": {
            "$ref": "#/components/schemas/DatasetStatus"
          },
          "data_count": {
            "type": "integer"
          },
          "trigger": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/DatasetTrigger"
              },
              {
                "type": "null"
              }
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "status",
          "data_count",
          "trigger",
          "created_at"
        ]
      },
      "Bot": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Bot public id (16 hex characters)."
          },
          "name": {
            "type": "string"
          },
          "description": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "schedule_group": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/ScheduleGroup"
              },
              {
                "type": "null"
              }
            ]
          },
          "union": {
            "type": "boolean",
            "description": "Whether collected data is appended to one dataset."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "worker_source": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/WorkerSource"
              },
              {
                "type": "null"
              }
            ]
          },
          "credit_per_item": {
            "oneOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          },
          "plans_count": {
            "oneOf": [
              {
                "type": "integer",
                "description": "Number of plans. `null` when multiple plans are not enabled for this account."
              },
              {
                "type": "null"
              }
            ]
          },
          "active_plans": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ActivePlan"
            }
          },
          "period_summary": {
            "oneOf": [
              {
                "type": "string",
                "description": "Enabled plans in one line."
              },
              {
                "type": "null"
              }
            ]
          },
          "next_run_at": {
            "oneOf": [
              {
                "type": "string",
                "description": "Nearest next run among enabled plans.",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ]
          },
          "latest_dataset": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/LatestDataset"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "id",
          "name",
          "description",
          "schedule_group",
          "union",
          "created_at",
          "updated_at",
          "worker_source",
          "credit_per_item",
          "plans_count",
          "active_plans",
          "period_summary",
          "next_run_at",
          "latest_dataset"
        ]
      },
      "NotificationsSummary": {
        "type": "object",
        "properties": {
          "webhook": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean"
              }
            },
            "required": [
              "enabled"
            ]
          },
          "slack": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean"
              },
              "channel": {
                "oneOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            },
            "required": [
              "enabled",
              "channel"
            ]
          }
        },
        "required": [
          "webhook",
          "slack"
        ]
      },
      "BotDetail": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Bot"
          },
          {
            "type": "object",
            "properties": {
              "settings": {
                "type": "object",
                "properties": {
                  "input_mode": {
                    "type": "string",
                    "enum": [
                      "direct",
                      "excel"
                    ]
                  },
                  "union_enabled": {
                    "type": "boolean"
                  }
                },
                "required": [
                  "input_mode",
                  "union_enabled"
                ]
              },
              "notifications": {
                "$ref": "#/components/schemas/NotificationsSummary"
              }
            },
            "required": [
              "settings",
              "notifications"
            ]
          }
        ]
      },
      "InputOption": {
        "type": "object",
        "properties": {
          "name": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "name_en": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "value": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "name",
          "name_en",
          "value"
        ]
      },
      "InputDefinition": {
        "type": "object",
        "properties": {
          "key": {
            "type": "string",
            "description": "`param1`..`param10`.",
            "pattern": "^param([1-9]|10)$"
          },
          "name": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "name_en": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "alias": {
            "oneOf": [
              {
                "type": "string",
                "description": "Alternative input name accepted in request bodies."
              },
              {
                "type": "null"
              }
            ]
          },
          "type": {
            "type": "string",
            "enum": [
              "text",
              "select"
            ]
          },
          "required": {
            "type": "boolean"
          },
          "options": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/InputOption"
            }
          },
          "excel_supported": {
            "type": "boolean"
          }
        },
        "required": [
          "key",
          "name",
          "name_en",
          "alias",
          "type",
          "required",
          "options",
          "excel_supported"
        ]
      },
      "BotInputs": {
        "type": "object",
        "properties": {
          "bot_id": {
            "type": "string"
          },
          "excel_supported": {
            "type": "boolean"
          },
          "inputs": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/InputDefinition"
            }
          }
        },
        "required": [
          "bot_id",
          "excel_supported",
          "inputs"
        ]
      },
      "InputValues": {
        "type": "object",
        "description": "Input values keyed by `paramN` or by the input alias. Values are strings or numbers.",
        "additionalProperties": {
          "oneOf": [
            {
              "type": "string",
              "maxLength": 5000
            },
            {
              "type": "number"
            }
          ]
        }
      },
      "ExcelFile": {
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "uploaded_at": {
                "type": "string",
                "format": "date-time"
              }
            },
            "required": [
              "name",
              "uploaded_at"
            ]
          },
          {
            "type": "null"
          }
        ]
      },
      "UnionState": {
        "type": "object",
        "properties": {
          "enabled": {
            "type": "boolean"
          },
          "target_dataset_id": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "enabled",
          "target_dataset_id"
        ]
      },
      "BotSettings": {
        "type": "object",
        "properties": {
          "bot_id": {
            "type": "string"
          },
          "inputs": {
            "type": "object",
            "additionalProperties": {
              "type": "object",
              "properties": {
                "name": {
                  "oneOf": [
                    {
                      "type": "string"
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "value": {
                  "oneOf": [
                    {
                      "type": "string"
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              },
              "required": [
                "name",
                "value"
              ]
            }
          },
          "input_mode": {
            "type": "string",
            "enum": [
              "direct",
              "excel"
            ]
          },
          "excel_file": {
            "$ref": "#/components/schemas/ExcelFile"
          },
          "union": {
            "$ref": "#/components/schemas/UnionState"
          },
          "plans_out_of_sync": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "plan_id": {
                  "$ref": "#/components/schemas/PlanId"
                },
                "name": {
                  "type": "string"
                },
                "label": {
                  "type": "string"
                },
                "changes": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "key": {
                        "type": "string"
                      },
                      "name": {
                        "oneOf": [
                          {
                            "type": "string"
                          },
                          {
                            "type": "null"
                          }
                        ]
                      },
                      "plan_value": {
                        "oneOf": [
                          {
                            "type": "string"
                          },
                          {
                            "type": "null"
                          }
                        ]
                      },
                      "bot_value": {
                        "oneOf": [
                          {
                            "type": "string"
                          },
                          {
                            "type": "null"
                          }
                        ]
                      }
                    },
                    "required": [
                      "key",
                      "name",
                      "plan_value",
                      "bot_value"
                    ]
                  }
                }
              },
              "required": [
                "plan_id",
                "name",
                "label",
                "changes"
              ]
            }
          }
        },
        "required": [
          "bot_id",
          "inputs",
          "input_mode",
          "excel_file",
          "union"
        ],
        "description": "`plans_out_of_sync` appears on PATCH responses when the change leaves plans with different values."
      },
      "BotSettingsUpdateRequest": {
        "type": "object",
        "properties": {
          "inputs": {
            "$ref": "#/components/schemas/InputValues"
          },
          "input_mode": {
            "type": "string",
            "enum": [
              "direct",
              "excel"
            ]
          },
          "union": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean"
              },
              "target_dataset_id": {
                "oneOf": [
                  {
                    "type": "integer"
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            },
            "required": []
          }
        },
        "required": [],
        "description": "Send at least one of the fields."
      },
      "ExcelUploadRequest": {
        "type": "object",
        "properties": {
          "file": {
            "type": "string",
            "contentMediaType": "application/octet-stream",
            "description": ".xlsx, .xls or .csv, at most 20MB."
          }
        },
        "required": [
          "file"
        ]
      },
      "ExcelUploadResult": {
        "type": "object",
        "properties": {
          "bot_id": {
            "type": "string"
          },
          "detected_type": {
            "type": "string",
            "enum": [
              "xlsx",
              "xls",
              "csv"
            ]
          },
          "file": {
            "$ref": "#/components/schemas/ExcelFile"
          },
          "rows": {
            "type": "integer"
          },
          "columns": {
            "type": "integer"
          },
          "first_row": {
            "type": "object",
            "additionalProperties": {
              "type": "object",
              "properties": {
                "name": {
                  "oneOf": [
                    {
                      "type": "string"
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "value": {
                  "oneOf": [
                    {
                      "type": "string"
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              },
              "required": [
                "name",
                "value"
              ]
            }
          }
        },
        "required": [
          "bot_id",
          "detected_type",
          "file",
          "rows",
          "columns",
          "first_row"
        ]
      },
      "Notifications": {
        "type": "object",
        "properties": {
          "bot_id": {
            "type": "string"
          },
          "webhook_url": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "webhook_enabled": {
            "type": "boolean"
          },
          "webhook_token_set": {
            "type": "boolean",
            "description": "The token value is never returned."
          },
          "last_delivery": {
            "oneOf": [
              {
                "type": "object",
                "properties": {
                  "kind": {
                    "type": "string"
                  },
                  "status": {
                    "type": "string",
                    "enum": [
                      "success",
                      "failed"
                    ]
                  },
                  "http_status": {
                    "type": "integer"
                  },
                  "at": {
                    "type": "string",
                    "format": "date-time"
                  }
                },
                "required": [
                  "kind",
                  "status",
                  "http_status",
                  "at"
                ]
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "bot_id",
          "webhook_url",
          "webhook_enabled",
          "webhook_token_set",
          "last_delivery"
        ]
      },
      "NotificationsUpdateRequest": {
        "type": "object",
        "properties": {
          "webhook_url": {
            "oneOf": [
              {
                "type": "string",
                "description": "http:// or https:// URL, at most 255 characters. `null` removes the webhook.",
                "maxLength": 255
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "webhook_url"
        ]
      },
      "WebhookTestResult": {
        "type": "object",
        "properties": {
          "bot_id": {
            "type": "string"
          },
          "success": {
            "type": "boolean"
          },
          "http_status": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "timed_out": {
            "type": "boolean"
          },
          "elapsed_ms": {
            "type": "integer"
          },
          "error": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "bot_id",
          "success",
          "http_status",
          "timed_out",
          "elapsed_ms",
          "error"
        ]
      },
      "BotRef": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "name"
        ]
      },
      "Dataset": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "bot": {
            "$ref": "#/components/schemas/BotRef"
          },
          "status": {
            "$ref": "#/components/schemas/DatasetStatus"
          },
          "data_count": {
            "type": "integer"
          },
          "union": {
            "type": "boolean"
          },
          "trigger": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/DatasetTrigger"
              },
              {
                "type": "null"
              }
            ]
          },
          "plan_id": {
            "oneOf": [
              {
                "type": "string",
                "description": "Id of the plan that started it, as a string."
              },
              {
                "type": "null"
              }
            ]
          },
          "credits_used": {
            "type": "integer"
          },
          "empty_reason": {
            "oneOf": [
              {
                "type": "string",
                "enum": [
                  "no_new_items",
                  "duplicates_only",
                  "not_found"
                ],
                "description": "Why a finished dataset has no data: no_new_items (nothing new in the collection period), duplicates_only (everything found was already collected), not_found (the target could not be found). null when the dataset has data or no reason was recorded."
              },
              {
                "type": "null"
              }
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "bot",
          "status",
          "data_count",
          "union",
          "trigger",
          "plan_id",
          "credits_used",
          "empty_reason",
          "created_at",
          "updated_at"
        ]
      },
      "DatasetPlan": {
        "type": "object",
        "properties": {
          "id": {
            "$ref": "#/components/schemas/PlanId"
          },
          "name": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "scheduled_at": {
            "oneOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "id"
        ],
        "description": "The plan that started the dataset (same as the webhook body, with the id as a string)."
      },
      "DatasetDetail": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "bot": {
            "$ref": "#/components/schemas/BotRef"
          },
          "status": {
            "$ref": "#/components/schemas/DatasetStatus"
          },
          "data_count": {
            "type": "integer"
          },
          "union": {
            "type": "boolean"
          },
          "trigger": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/DatasetTrigger"
              },
              {
                "type": "null"
              }
            ]
          },
          "credits_used": {
            "type": "integer"
          },
          "empty_reason": {
            "oneOf": [
              {
                "type": "string",
                "enum": [
                  "no_new_items",
                  "duplicates_only",
                  "not_found"
                ],
                "description": "Why a finished dataset has no data: no_new_items (nothing new in the collection period), duplicates_only (everything found was already collected), not_found (the target could not be found). null when the dataset has data or no reason was recorded."
              },
              {
                "type": "null"
              }
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "plan": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/DatasetPlan"
              },
              {
                "type": "null"
              }
            ]
          },
          "inputs": {
            "oneOf": [
              {
                "type": "object",
                "additionalProperties": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "oneOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "value": {
                      "oneOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  },
                  "required": [
                    "name",
                    "value"
                  ]
                }
              },
              {
                "type": "null"
              }
            ],
            "description": "Input values used. `null` for union datasets filled from Excel rows."
          },
          "started_at": {
            "oneOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ]
          },
          "elapsed_sec": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "id",
          "bot",
          "status",
          "data_count",
          "union",
          "trigger",
          "credits_used",
          "empty_reason",
          "created_at",
          "updated_at",
          "plan",
          "inputs",
          "started_at",
          "elapsed_sec"
        ],
        "description": "Dataset summary plus plan, inputs and timing. Unlike the list, `plan_id` is replaced by `plan`."
      },
      "ResultRow": {
        "type": "object",
        "required": [
          "id",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "id": {
            "type": "integer"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        },
        "additionalProperties": true,
        "description": "One collected row. Besides `id`, `created_at` and `updated_at`, the keys are the bot's own column names."
      },
      "Time24": {
        "type": "string",
        "description": "HH:MM (24-hour, KST).",
        "pattern": "^([01][0-9]|2[0-3]):[0-5][0-9]$"
      },
      "WhenInterval": {
        "type": "object",
        "properties": {
          "type": {
            "const": "interval"
          },
          "minutes": {
            "type": "integer",
            "enum": [
              10,
              20,
              30,
              60,
              120,
              180,
              240,
              360,
              480,
              720
            ]
          }
        },
        "required": [
          "type",
          "minutes"
        ],
        "description": "Every N minutes."
      },
      "WhenDaily": {
        "type": "object",
        "properties": {
          "type": {
            "const": "daily"
          },
          "times": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Time24"
            }
          }
        },
        "required": [
          "type",
          "times"
        ],
        "description": "Every day at the given times."
      },
      "WhenDays": {
        "type": "object",
        "properties": {
          "type": {
            "const": "days"
          },
          "every_days": {
            "type": "integer",
            "minimum": 2
          },
          "anchor": {
            "type": "string",
            "description": "Date the cycle counts from (YYYY-MM-DD). Optional on requests.",
            "format": "date"
          },
          "times": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Time24"
            }
          }
        },
        "required": [
          "type",
          "every_days",
          "times"
        ],
        "description": "Every N days (N >= 2)."
      },
      "WhenWeekly": {
        "type": "object",
        "properties": {
          "type": {
            "const": "weekly"
          },
          "every_weeks": {
            "type": "integer",
            "minimum": 1
          },
          "anchor": {
            "type": "string",
            "description": "Date the cycle counts from (YYYY-MM-DD). Optional on requests.",
            "format": "date"
          },
          "days": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "sun",
                "mon",
                "tue",
                "wed",
                "thu",
                "fri",
                "sat"
              ]
            }
          },
          "times": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Time24"
            }
          }
        },
        "required": [
          "type",
          "days",
          "times"
        ],
        "description": "On the given weekdays, every N weeks (default 1)."
      },
      "WhenMonthly": {
        "type": "object",
        "properties": {
          "type": {
            "const": "monthly"
          },
          "dates": {
            "type": "array",
            "items": {
              "oneOf": [
                {
                  "type": "integer",
                  "minimum": 1,
                  "maximum": 31
                },
                {
                  "const": "last"
                }
              ]
            }
          },
          "times": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Time24"
            }
          }
        },
        "required": [
          "type",
          "dates",
          "times"
        ],
        "description": "On the given days of the month (1-31 or \"last\")."
      },
      "When": {
        "oneOf": [
          {
            "$ref": "#/components/schemas/WhenInterval"
          },
          {
            "$ref": "#/components/schemas/WhenDaily"
          },
          {
            "$ref": "#/components/schemas/WhenDays"
          },
          {
            "$ref": "#/components/schemas/WhenWeekly"
          },
          {
            "$ref": "#/components/schemas/WhenMonthly"
          }
        ],
        "discriminator": {
          "propertyName": "type",
          "mapping": {
            "interval": "#/components/schemas/WhenInterval",
            "daily": "#/components/schemas/WhenDaily",
            "days": "#/components/schemas/WhenDays",
            "weekly": "#/components/schemas/WhenWeekly",
            "monthly": "#/components/schemas/WhenMonthly"
          }
        },
        "description": "When a plan runs. Five types can be sent. `manual` (no schedule) and `custom` (an expression the API cannot edit) only appear in responses."
      },
      "WhenResponse": {
        "oneOf": [
          {
            "$ref": "#/components/schemas/When"
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "const": "manual"
              }
            },
            "required": [
              "type"
            ]
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "const": "custom"
              },
              "editable": {
                "const": false
              }
            },
            "required": [
              "type",
              "editable"
            ]
          }
        ]
      },
      "PlanCondition": {
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "name": {
                "oneOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "value": {
                "oneOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            },
            "required": [
              "name",
              "value"
            ]
          },
          {
            "type": "object",
            "properties": {
              "excel": {
                "const": true
              }
            },
            "required": [
              "excel"
            ]
          },
          {
            "type": "object",
            "properties": {
              "more": {
                "type": "integer"
              }
            },
            "required": [
              "more"
            ]
          }
        ],
        "description": "One condition shown for the plan: an input, Excel input, or \"N more\"."
      },
      "Plan": {
        "type": "object",
        "properties": {
          "id": {
            "$ref": "#/components/schemas/PlanId"
          },
          "bot_id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "enabled": {
            "type": "boolean"
          },
          "linked": {
            "type": "boolean",
            "description": "True when the plan follows the bot settings."
          },
          "when": {
            "$ref": "#/components/schemas/WhenResponse"
          },
          "label": {
            "type": "string",
            "description": "Period sentence in Korean."
          },
          "label_en": {
            "type": "string",
            "description": "Period sentence in English."
          },
          "inputs": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "conditions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PlanCondition"
            }
          },
          "input_mode": {
            "type": "string",
            "enum": [
              "direct",
              "excel"
            ]
          },
          "union": {
            "$ref": "#/components/schemas/UnionState"
          },
          "next_runs": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "date-time"
            }
          }
        },
        "required": [
          "id",
          "bot_id",
          "name",
          "enabled",
          "linked",
          "when",
          "label",
          "label_en",
          "inputs",
          "conditions",
          "input_mode",
          "union",
          "next_runs"
        ]
      },
      "PlanList": {
        "type": "object",
        "properties": {
          "bot_id": {
            "type": "string"
          },
          "plans": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Plan"
            }
          }
        },
        "required": [
          "bot_id",
          "plans"
        ]
      },
      "PlanCreateRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "At most 20 characters. Omit for \"Plan N\".",
            "maxLength": 20
          },
          "when": {
            "$ref": "#/components/schemas/When"
          },
          "inputs": {
            "$ref": "#/components/schemas/InputValues"
          },
          "union": {
            "oneOf": [
              {
                "type": "boolean"
              },
              {
                "type": "object",
                "properties": {
                  "enabled": {
                    "type": "boolean"
                  }
                },
                "required": []
              }
            ],
            "description": "A new plan has no datasets yet, so `target_dataset_id` is not accepted here."
          },
          "enabled": {
            "type": "boolean"
          },
          "input_mode": {
            "const": "direct"
          }
        },
        "required": [
          "when"
        ]
      },
      "PlanUpdateRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 20
          },
          "enabled": {
            "type": "boolean"
          },
          "when": {
            "$ref": "#/components/schemas/When"
          },
          "inputs": {
            "$ref": "#/components/schemas/InputValues"
          },
          "union": {
            "oneOf": [
              {
                "type": "boolean"
              },
              {
                "type": "object",
                "properties": {
                  "enabled": {
                    "type": "boolean"
                  },
                  "target_dataset_id": {
                    "oneOf": [
                      {
                        "type": "integer"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                },
                "required": []
              }
            ]
          },
          "input_mode": {
            "const": "direct"
          }
        },
        "required": [],
        "description": "Send at least one of name, enabled, when, inputs, union, input_mode. `input_mode: \"excel\"` is not supported yet."
      },
      "PlanDeleted": {
        "type": "object",
        "properties": {
          "id": {
            "$ref": "#/components/schemas/PlanId"
          },
          "deleted": {
            "const": true
          }
        },
        "required": [
          "id",
          "deleted"
        ]
      },
      "CopySettingsRequest": {
        "type": "object",
        "properties": {
          "fields": {
            "type": "array",
            "items": {
              "type": "string",
              "description": "Input name or `paramN`."
            }
          }
        },
        "required": [],
        "description": "Omit `fields` to copy every input the bot uses."
      },
      "PlanCopyResult": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Plan"
          },
          {
            "type": "object",
            "properties": {
              "copied_fields": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            },
            "required": [
              "copied_fields"
            ]
          }
        ]
      },
      "PlanPreviewRequest": {
        "type": "object",
        "properties": {
          "when": {
            "$ref": "#/components/schemas/When"
          },
          "count": {
            "type": "integer",
            "description": "How many runs to list (1-20, default 5).",
            "minimum": 1,
            "maximum": 20
          }
        },
        "required": [],
        "description": "Omit `when` to preview the plan as it is now."
      },
      "PlanPreview": {
        "type": "object",
        "properties": {
          "id": {
            "$ref": "#/components/schemas/PlanId"
          },
          "when": {
            "$ref": "#/components/schemas/WhenResponse"
          },
          "label": {
            "type": "string"
          },
          "label_en": {
            "type": "string"
          },
          "sentence": {
            "type": "object",
            "properties": {
              "ko": {
                "type": "string"
              },
              "en": {
                "type": "string"
              }
            },
            "required": [
              "ko",
              "en"
            ]
          },
          "next_runs": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "date-time"
            }
          },
          "runs_per_month": {
            "type": "number"
          }
        },
        "required": [
          "id",
          "when",
          "label",
          "label_en",
          "sentence",
          "next_runs",
          "runs_per_month"
        ]
      },
      "PlanRun": {
        "type": "object",
        "properties": {
          "scheduled_at": {
            "type": "string",
            "format": "date-time"
          },
          "state": {
            "type": "string",
            "enum": [
              "ran",
              "skipped",
              "missed",
              "upcoming"
            ]
          },
          "reason": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "dataset_id": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "scheduled_at",
          "state",
          "reason",
          "dataset_id"
        ]
      },
      "PlanRuns": {
        "type": "object",
        "properties": {
          "plan_id": {
            "$ref": "#/components/schemas/PlanId"
          },
          "source": {
            "type": "string"
          },
          "from": {
            "type": "string",
            "format": "date-time"
          },
          "to": {
            "oneOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ]
          },
          "counts": {
            "type": "object",
            "additionalProperties": {
              "type": "integer"
            }
          },
          "runs": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PlanRun"
            }
          }
        },
        "required": [
          "plan_id",
          "source",
          "from",
          "to",
          "counts",
          "runs"
        ]
      },
      "CollectionRequest": {
        "type": "object",
        "properties": {
          "inputs": {
            "$ref": "#/components/schemas/InputValues"
          },
          "save_to_settings": {
            "type": "boolean",
            "default": true,
            "description": "Also save the inputs to the bot settings (default true). `false` collects once with these inputs."
          }
        },
        "required": [],
        "description": "Omit `inputs` to collect with the saved bot settings."
      },
      "PlanAffected": {
        "type": "object",
        "properties": {
          "id": {
            "$ref": "#/components/schemas/PlanId"
          },
          "name": {
            "type": "string"
          },
          "label": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "name",
          "label"
        ]
      },
      "CollectionResult": {
        "allOf": [
          {
            "$ref": "#/components/schemas/DatasetDetail"
          },
          {
            "type": "object",
            "properties": {
              "saved_to_settings": {
                "type": "boolean"
              },
              "plans_affected": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/PlanAffected"
                }
              }
            },
            "required": [
              "saved_to_settings"
            ],
            "description": "`plans_affected` lists enabled plans that follow the bot settings and therefore changed too. Present only when multiple plans are enabled."
          }
        ]
      },
      "BulkRequest": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "minItems": 1,
            "maxItems": 100,
            "items": {
              "type": "object",
              "properties": {
                "bot_id": {
                  "type": "string"
                },
                "inputs": {
                  "$ref": "#/components/schemas/InputValues"
                },
                "save_to_settings": {
                  "type": "boolean",
                  "default": true
                }
              },
              "required": [
                "bot_id"
              ]
            }
          }
        },
        "required": [
          "items"
        ]
      },
      "BulkItem": {
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "bot_id": {
                "type": "string"
              },
              "success": {
                "const": true
              },
              "dataset": {
                "$ref": "#/components/schemas/Dataset"
              },
              "saved_to_settings": {
                "type": "boolean"
              },
              "plans_affected": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/PlanAffected"
                }
              }
            },
            "required": [
              "bot_id",
              "success",
              "dataset",
              "saved_to_settings"
            ]
          },
          {
            "type": "object",
            "properties": {
              "bot_id": {
                "oneOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "success": {
                "const": false
              },
              "code": {
                "$ref": "#/components/schemas/ErrorCode"
              },
              "message": {
                "type": "string"
              },
              "details": {
                "type": "object",
                "additionalProperties": true
              }
            },
            "required": [
              "bot_id",
              "success",
              "code",
              "message"
            ]
          }
        ],
        "description": "Result of one bot, in request order. One failure does not stop the others."
      },
      "BulkResult": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BulkItem"
            }
          }
        },
        "required": [
          "items"
        ]
      },
      "BulkExtra": {
        "type": "object",
        "properties": {
          "result": {
            "type": "string",
            "enum": [
              "success",
              "partial_success",
              "failure"
            ]
          },
          "count": {
            "type": "integer"
          },
          "success_count": {
            "type": "integer"
          },
          "failure_count": {
            "type": "integer"
          }
        },
        "required": [
          "result",
          "count",
          "success_count",
          "failure_count"
        ],
        "description": "Counts for bulk collection."
      },
      "BulkJobRequest": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "minItems": 1,
            "maxItems": 5000,
            "items": {
              "type": "object",
              "properties": {
                "bot_id": {
                  "type": "string"
                },
                "inputs": {
                  "$ref": "#/components/schemas/InputValues"
                },
                "save_to_settings": {
                  "type": "boolean",
                  "default": true
                }
              },
              "required": [
                "bot_id"
              ]
            },
            "description": "Same item shape as bulk collection. Items are checked when they are processed: a bad item fails on its own, like in bulk collection."
          }
        },
        "required": [
          "items"
        ]
      },
      "BulkJobStatus": {
        "type": "string",
        "enum": [
          "queued",
          "running",
          "done"
        ],
        "description": "`queued` accepted, `running` being processed, `done` every item processed."
      },
      "BulkJobAccepted": {
        "type": "object",
        "properties": {
          "job": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "Job id (`bj_` + 24 hex characters)."
              },
              "status": {
                "$ref": "#/components/schemas/BulkJobStatus"
              },
              "total": {
                "type": "integer",
                "description": "Number of items."
              },
              "created_at": {
                "type": "string",
                "format": "date-time"
              }
            },
            "required": [
              "id",
              "status",
              "total",
              "created_at"
            ]
          }
        },
        "required": [
          "job"
        ]
      },
      "BulkJobPendingItem": {
        "type": "object",
        "properties": {
          "bot_id": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "success": {
            "type": "null"
          }
        },
        "required": [
          "bot_id",
          "success"
        ],
        "description": "An item not processed yet."
      },
      "BulkJobDetail": {
        "type": "object",
        "properties": {
          "job": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "status": {
                "$ref": "#/components/schemas/BulkJobStatus"
              },
              "total": {
                "type": "integer"
              },
              "created_at": {
                "type": "string",
                "format": "date-time"
              },
              "processed": {
                "type": "integer",
                "description": "Processed items."
              },
              "success_count": {
                "type": "integer"
              },
              "failure_count": {
                "type": "integer"
              },
              "started_at": {
                "oneOf": [
                  {
                    "type": "string",
                    "format": "date-time"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "finished_at": {
                "oneOf": [
                  {
                    "type": "string",
                    "format": "date-time"
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            },
            "required": [
              "id",
              "status",
              "total",
              "created_at",
              "processed",
              "success_count",
              "failure_count",
              "started_at",
              "finished_at"
            ]
          },
          "items": {
            "type": "array",
            "items": {
              "oneOf": [
                {
                  "$ref": "#/components/schemas/BulkItem"
                },
                {
                  "$ref": "#/components/schemas/BulkJobPendingItem"
                }
              ]
            }
          }
        },
        "required": [
          "job",
          "items"
        ],
        "description": "`items` is one page of items in request order. A processed item has the same shape and values as an item of bulk collection."
      },
      "HealthData": {
        "type": "object",
        "properties": {
          "status": {
            "const": "ok"
          },
          "time": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "status",
          "time"
        ]
      },
      "MeData": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string"
          },
          "name": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "email",
          "name"
        ]
      }
    }
  }
}
