# Start a fresh tenant-scoped research scroll for the configured workspace (/docs/api-reference/v1/scrolls/post)

`POST https://api.viralquery.com/v1/scrolls`

Start a fresh tenant-scoped research scroll for the configured workspace

Operation ID: `createScroll`

OpenAPI document: https://viralquery.com/openapi.json

## Authentication

Bearer token: `Authorization: Bearer $VIRALQUERY_API_KEY`

## Request

### Request body — application/json (required)

```json
{
  "type": "object",
  "properties": {
    "prompt": {
      "type": "string",
      "minLength": 1,
      "maxLength": 20000
    },
    "schedule": {
      "type": "integer",
      "minimum": 1,
      "maximum": 7
    },
    "template": {
      "type": "string",
      "minLength": 1,
      "maxLength": 100
    },
    "idempotencyKey": {
      "type": "string",
      "minLength": 8,
      "maxLength": 200
    }
  },
  "additionalProperties": false
}
```

## Responses

### `200` — Existing idempotent scroll

**application/json**

```json
{
  "type": "object",
  "properties": {
    "outcome": {
      "type": "string",
      "enum": [
        "queued",
        "existing"
      ]
    },
    "scroll": {
      "type": "object",
      "properties": {
        "id": {
          "type": "string"
        },
        "status": {
          "type": "string",
          "enum": [
            "queued",
            "running",
            "completed",
            "failed",
            "cancelled"
          ]
        },
        "stage": {
          "type": "string",
          "nullable": true
        },
        "progress": {
          "type": "object",
          "properties": {
            "percent": {
              "type": "number",
              "minimum": 0,
              "maximum": 100
            },
            "dispatchAttempts": {
              "type": "integer",
              "minimum": 0
            }
          },
          "description": "Stage-variable progress. Known fields are percent (0-100) and dispatchAttempts; later stages may add documented fields."
        },
        "resultCounts": {
          "type": "object",
          "properties": {
            "videos": {
              "type": "integer",
              "minimum": 0
            }
          },
          "description": "Terminal result counts. videos is the known archived-video count; later result types may add documented fields."
        },
        "failureCode": {
          "type": "string",
          "nullable": true
        },
        "schedule": {
          "type": "integer",
          "nullable": true
        },
        "template": {
          "type": "string",
          "nullable": true
        },
        "createdAt": {
          "type": "number"
        },
        "updatedAt": {
          "type": "number"
        },
        "startedAt": {
          "type": "number",
          "nullable": true
        },
        "completedAt": {
          "type": "number",
          "nullable": true
        }
      },
      "required": [
        "id",
        "status",
        "stage",
        "progress",
        "resultCounts",
        "failureCode",
        "schedule",
        "template",
        "createdAt",
        "updatedAt",
        "startedAt",
        "completedAt"
      ]
    }
  },
  "required": [
    "outcome",
    "scroll"
  ]
}
```

### `202` — Accepted (new scroll queued)

**application/json**

```json
{
  "type": "object",
  "properties": {
    "outcome": {
      "type": "string",
      "enum": [
        "queued",
        "existing"
      ]
    },
    "scroll": {
      "type": "object",
      "properties": {
        "id": {
          "type": "string"
        },
        "status": {
          "type": "string",
          "enum": [
            "queued",
            "running",
            "completed",
            "failed",
            "cancelled"
          ]
        },
        "stage": {
          "type": "string",
          "nullable": true
        },
        "progress": {
          "type": "object",
          "properties": {
            "percent": {
              "type": "number",
              "minimum": 0,
              "maximum": 100
            },
            "dispatchAttempts": {
              "type": "integer",
              "minimum": 0
            }
          },
          "description": "Stage-variable progress. Known fields are percent (0-100) and dispatchAttempts; later stages may add documented fields."
        },
        "resultCounts": {
          "type": "object",
          "properties": {
            "videos": {
              "type": "integer",
              "minimum": 0
            }
          },
          "description": "Terminal result counts. videos is the known archived-video count; later result types may add documented fields."
        },
        "failureCode": {
          "type": "string",
          "nullable": true
        },
        "schedule": {
          "type": "integer",
          "nullable": true
        },
        "template": {
          "type": "string",
          "nullable": true
        },
        "createdAt": {
          "type": "number"
        },
        "updatedAt": {
          "type": "number"
        },
        "startedAt": {
          "type": "number",
          "nullable": true
        },
        "completedAt": {
          "type": "number",
          "nullable": true
        }
      },
      "required": [
        "id",
        "status",
        "stage",
        "progress",
        "resultCounts",
        "failureCode",
        "schedule",
        "template",
        "createdAt",
        "updatedAt",
        "startedAt",
        "completedAt"
      ]
    }
  },
  "required": [
    "outcome",
    "scroll"
  ]
}
```

### `400` — Invalid request (input failed validation)

**application/json**

```json
{
  "type": "object",
  "properties": {
    "error": {
      "type": "string",
      "enum": [
        "invalid_request"
      ],
      "description": "Stable machine-readable error code."
    },
    "message": {
      "type": "string",
      "description": "Human-readable summary."
    },
    "issues": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "path": {
            "type": "string"
          },
          "message": {
            "type": "string"
          }
        },
        "required": [
          "path",
          "message"
        ]
      },
      "description": "First-class Zod validation issues (path + message), not a stringified blob."
    }
  },
  "required": [
    "error",
    "message",
    "issues"
  ]
}
```

### `401` — Unauthorized (missing or invalid API key)

**application/json**

```json
{
  "anyOf": [
    {
      "type": "object",
      "properties": {
        "error": {
          "type": "string",
          "enum": [
            "unauthorized"
          ]
        },
        "message": {
          "type": "string"
        },
        "subscribeUrl": {
          "type": "string",
          "description": "Human-clickable ViralQuery pricing and subscription URL."
        }
      },
      "required": [
        "error",
        "message",
        "subscribeUrl"
      ]
    },
    {
      "type": "object",
      "properties": {
        "error": {
          "type": "string",
          "enum": [
            "auth_required"
          ]
        },
        "message": {
          "type": "string",
          "description": "The session-scoped key is expired or no longer resolves to its account."
        }
      },
      "required": [
        "error",
        "message"
      ]
    }
  ]
}
```

### `402` — Payment Required (active subscription required)

**application/json**

```json
{
  "type": "object",
  "properties": {
    "error": {
      "type": "string",
      "enum": [
        "subscription_required"
      ]
    },
    "message": {
      "type": "string"
    },
    "subscribeUrl": {
      "type": "string",
      "description": "Human-clickable ViralQuery pricing and subscription URL."
    }
  },
  "required": [
    "error",
    "message",
    "subscribeUrl"
  ]
}
```

### `403` — Forbidden (scope or plan is insufficient)

**application/json**

```json
{
  "type": "object",
  "properties": {
    "error": {
      "type": "string",
      "enum": [
        "forbidden"
      ]
    },
    "message": {
      "type": "string"
    },
    "requiredScope": {
      "type": "string",
      "description": "Scope or explicit session capability required by this operation."
    },
    "grantedScopes": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "Scopes present on the calling key."
    }
  },
  "required": [
    "error",
    "message",
    "requiredScope",
    "grantedScopes"
  ]
}
```

### `409` — Conflict or operation error

**application/json**

```json
{
  "anyOf": [
    {
      "type": "object",
      "properties": {
        "error": {
          "type": "string",
          "enum": [
            "workspace_required"
          ]
        },
        "message": {
          "type": "string"
        }
      },
      "required": [
        "error",
        "message"
      ]
    },
    {
      "type": "object",
      "properties": {
        "error": {
          "type": "string",
          "enum": [
            "scroll_active_limit"
          ]
        },
        "message": {
          "type": "string"
        }
      },
      "required": [
        "error",
        "message"
      ]
    },
    {
      "type": "object",
      "properties": {
        "error": {
          "type": "string",
          "enum": [
            "operation_error"
          ]
        },
        "message": {
          "type": "string",
          "description": "The operation failed while handling the request."
        }
      },
      "required": [
        "error",
        "message"
      ]
    }
  ]
}
```

### `429` — Too Many Requests (rate limited)

**application/json**

```json
{
  "type": "object",
  "properties": {
    "error": {
      "type": "string",
      "enum": [
        "rate_limited"
      ]
    },
    "message": {
      "type": "string"
    },
    "retryAfter": {
      "type": "number",
      "description": "Seconds to wait before retrying (mirrors the Retry-After header)."
    }
  },
  "required": [
    "error",
    "message",
    "retryAfter"
  ]
}
```