> ## Documentation Index
> Fetch the complete documentation index at: https://wordsmithai.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Create Agent Question

> Ask a question to the Wordsmith AI agent with optional file attachments

Creates a new agent session by asking a question, or adds a question to an existing session. The agent can analyze text, documents, and provide legal insights based on the question and any attached files.

When adding questions to an existing session, the conversation context is preserved, allowing for follow-up questions and multi-turn conversations.

## Authentication

This endpoint requires a valid API key in the Authorization header.

## Path Parameters

<ParamField path="agent_id" type="string" default="default" required>
  The agent to ask. Accepts the agent id shown in the app, the `id` returned by
  [List Agents](/api-reference/agents/list-agents), or `"default"` for the general
  Wordsmith agent.
</ParamField>

## Request Body

<ParamField body="question" type="string" required>
  The question to ask the agent. Maximum length: 10,000 characters.
</ParamField>

<ParamField body="attachments" type="array">
  An array of file attachments (maximum 10 files). Each attachment can be either
  an uploaded file or a URL.

  <Expandable title="Attachment Object">
    <ParamField body="upload_job_id" type="string">
      The upload job ID returned from the file upload endpoint. Either this or
      `url` must be provided.
    </ParamField>

    <ParamField body="url" type="string">
      A publicly accessible URL to download the file. Either this or
      `upload_job_id` must be provided.
    </ParamField>

    <ParamField body="unzip" type="boolean" default="false">
      Whether to automatically extract ZIP archives and process individual files
      within them.
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="session_id" type="string">
  The session ID to add this question to. If not provided, a new session will be
  created. When adding to an existing session, the conversation context is
  preserved for follow-up questions.
</ParamField>

<ParamField body="permissions" type="object">
  Optional permissions settings for the chat session.

  <Expandable title="Permissions Object">
    <ParamField body="visibility" type="string" required>
      The visibility level for the chat session. Controls who can access the
      session: <br /> • `"private"`: Only you can access the session <br /> •
      `"organization"`: Anyone in your organization can access the session
      <br /> • `"public"`: Anyone with the link can access the session
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="callback_url" type="string">
  URL to receive a webhook notification when async processing is complete. Only
  used when `sync_mode` is `false`. Optionally signed with the webhook secret if
  provided when creating a new API key. Signature is in the
  `Wordsmith-Signature` header.
</ParamField>

<ParamField body="sync_mode" type="boolean" default="false">
  Whether to wait for the complete response synchronously. `true`: Response
  includes the full answer (30-second timeout). `false`: Returns immediately
  with a session ID for async processing.
</ParamField>

<CodeGroup>
  ```bash cURL - Simple Question theme={null}
  curl -X POST "https://api.wordsmith.ai/api/v1/agents/default/questions" \
    -H "Authorization: Bearer sk-ws-api1-your_api_key_here" \
    -H "Content-Type: application/json" \
    -d '{
      "question": "What are the key elements of a valid contract under US law?",
      "sync_mode": true
    }'
  ```

  ```bash cURL - With File Attachment theme={null}
  curl -X POST "https://api.wordsmith.ai/api/v1/agents/default/questions" \
    -H "Authorization: Bearer sk-ws-api1-your_api_key_here" \
    -H "Content-Type: application/json" \
    -d '{
      "question": "Please review this contract and identify any potential issues",
      "attachments": [
        {
          "upload_job_id": "123e4567-e89b-12d3-a456-426614174000"
        }
      ],
      "sync_mode": false,
      "callback_url": "https://your-app.com/webhooks/wordsmith"
    }'
  ```

  ```bash cURL - With URL Attachment theme={null}
  curl -X POST "https://api.wordsmith.ai/api/v1/agents/default/questions" \
    -H "Authorization: Bearer sk-ws-api1-your_api_key_here" \
    -H "Content-Type: application/json" \
    -d '{
      "question": "Analyze this public document",
      "attachments": [
        {
          "url": "https://example.com/public-document.pdf"
        }
      ],
      "sync_mode": false
    }'
  ```

  ```bash cURL - Add Question to Existing Session theme={null}
  curl -X POST "https://api.wordsmith.ai/api/v1/agents/default/questions" \
    -H "Authorization: Bearer sk-ws-api1-your_api_key_here" \
    -H "Content-Type: application/json" \
    -d '{
      "question": "Can you elaborate on the liability clause you mentioned?",
      "session_id": "550e8400-e29b-41d4-a716-446655440000",
      "sync_mode": false
    }'
  ```

  ```bash cURL - With Session Permissions theme={null}
  curl -X POST "https://api.wordsmith.ai/api/v1/agents/default/questions" \
    -H "Authorization: Bearer sk-ws-api1-your_api_key_here" \
    -H "Content-Type: application/json" \
    -d '{
      "question": "Review this contract for potential issues",
      "attachments": [
        {
          "upload_job_id": "123e4567-e89b-12d3-a456-426614174000"
        }
      ],
      "permissions": {
        "visibility": "organization"
      },
      "sync_mode": false
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch(
    "https://api.wordsmith.ai/api/v1/agents/default/questions",
    {
      method: "POST",
      headers: {
        Authorization: "Bearer sk-ws-api1-your_api_key_here",
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        question: "What are the implications of this clause?",
        attachments: [
          {
            upload_job_id: "123e4567-e89b-12d3-a456-426614174000",
          },
        ],
        permissions: {
          visibility: "organization",
        },
        sync_mode: false,
        callback_url: "https://your-app.com/webhooks/wordsmith",
      }),
    }
  );

  const result = await response.json();
  ```

  ```python Python theme={null}
  import requests

  headers = {
      "Authorization": "Bearer sk-ws-api1-your_api_key_here",
      "Content-Type": "application/json"
  }

  data = {
      "question": "Please summarize the key terms in this agreement",
      "attachments": [
          {
              "upload_job_id": "upload_abc123def456"
          }
      ],
      "permissions": {
          "visibility": "organization"
      },
      "sync_mode": False,
      "callback_url": "https://your-app.com/webhooks/wordsmith"
  }

  response = requests.post(
      "https://api.wordsmith.ai/api/v1/agents/default/questions",
      headers=headers,
      json=data
  )
  result = response.json()
  ```
</CodeGroup>

## Response

<ResponseField name="id" type="string">
  The unique identifier for this specific question. Always usable to check the
  question's status, including when `status` is `"filtered"`.
</ResponseField>

<ResponseField name="session_id" type="string" nullable>
  The session ID that contains this question. This is always the same for all
  questions within a conversation session. `null` only when `status` is
  `"filtered"`, where no session was created.
</ResponseField>

<ResponseField name="session_url" type="string" nullable>
  A direct URL to view this session in the Wordsmith web application. This
  allows users to access the full conversation history and interact with the
  agent through the web interface. `null` only when `status` is
  `"filtered"`, where there is no session to view.
</ResponseField>

<ResponseField name="status" type="string">
  The current status of the question: `"in_progress"`: Processing is ongoing.
  `"completed"`: Answer is ready. `"error"`: Processing failed. `"filtered"`:
  The agent declined the question — see [Filtered
  questions](#filtered-questions).
</ResponseField>

<ResponseField name="answer" type="string" nullable>
  The agent's response to your question. Present when `status` is
  `"completed"`, and also when it is `"filtered"` — where it carries the
  decline wording, so a client that only reads `answer` still has something to
  show. See [Filtered questions](#filtered-questions).
</ResponseField>

<ResponseField name="attachments" type="array" nullable>
  Array of files generated by the agent (e.g., summary documents, analysis reports). Only present when `status` is `"completed"`.

  <Expandable title="Attachment Object">
    <ResponseField name="file_name" type="string" nullable>
      The name of the generated file
    </ResponseField>

    <ResponseField name="content_type" type="string" nullable>
      The MIME type of the file
    </ResponseField>

    <ResponseField name="content_length" type="integer" nullable>
      The size of the file in bytes
    </ResponseField>

    <ResponseField name="url" type="string">
      A presigned URL to download the file (expires after 24 hours)
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="reason" type="string" nullable>
  One sentence explaining why the agent declined the question. Present only when `status` is
  `"filtered"`, and `null` for every other status. It may also be `null` on a filtered question —
  see [Filtered questions](#filtered-questions) — so treat it as an explanation to show when you
  have one, not a field to depend on.
</ResponseField>

<ResponseExample>
  ```json Sync Mode - Completed Response theme={null}
  {
    "id": "123e4567-e89b-12d3-a456-426614174000",
    "session_id": "123e4567-e89b-12d3-a456-426614174000",
    "session_url": "https://app.wordsmith.ai/chat/123e4567-e89b-12d3-a456-426614174000",
    "status": "completed",
    "answer": "A valid contract under US law typically requires four essential elements:\n\n1. **Offer**: A clear, definite proposal to enter into an agreement...",
    "attachments": [
      {
        "file_name": "contract_analysis.pdf",
        "content_type": "application/pdf",
        "content_length": 245760,
        "url": "https://files.wordsmith.ai/signed-url-here"
      }
    ],
    "reason": null
  }
  ```

  ```json Async Mode - In Progress Response theme={null}
  {
    "id": "987fcdeb-51a2-43d1-9e8f-7b6c5a4d3e2f",
    "session_id": "987fcdeb-51a2-43d1-9e8f-7b6c5a4d3e2f",
    "session_url": "https://app.wordsmith.ai/chat/987fcdeb-51a2-43d1-9e8f-7b6c5a4d3e2f",
    "status": "in_progress",
    "answer": null,
    "attachments": null,
    "reason": null
  }
  ```

  ```json Follow-up Question in Existing Session theme={null}
  {
    "id": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
    "session_id": "550e8400-e29b-41d4-a716-446655440000",
    "session_url": "https://app.wordsmith.ai/chat/550e8400-e29b-41d4-a716-446655440000",
    "status": "in_progress",
    "answer": null,
    "attachments": null,
    "reason": null
  }
  ```

  ```json Error Response theme={null}
  {
    "id": "abcdef12-3456-7890-abcd-ef1234567890",
    "session_id": "abcdef12-3456-7890-abcd-ef1234567890",
    "session_url": "https://app.wordsmith.ai/chat/abcdef12-3456-7890-abcd-ef1234567890",
    "status": "error",
    "answer": "Unable to process the attached file. Please ensure the file is not corrupted and try again.",
    "attachments": null,
    "reason": null
  }
  ```

  ```json Filtered Response theme={null}
  {
    "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
    "session_id": null,
    "session_url": null,
    "status": "filtered",
    "answer": "This agent only handles commercial contract questions, and this one is about employment law.",
    "attachments": null,
    "reason": "This agent only handles commercial contract questions, and this one is about employment law."
  }
  ```
</ResponseExample>

## Filtered Questions

An agent can be configured with an **intake instruction** describing the work it accepts. When a new question does not match that instruction, the agent declines it: the request returns `status: "filtered"` and no session is created.

`"filtered"` is **not an error**. The request was well-formed and authenticated; the agent simply decided the question was not for it. Handle it as its own outcome rather than as a failure to retry.

Three things follow from no session existing:

* **`session_id` and `session_url` are `null`.** They are null for this status and no other, so existing handling for `"in_progress"`, `"completed"` and `"error"` is unaffected.
* **`id` is still valid.** It identifies the filtered question, and `GET /api/v1/agents/{agent_id}/questions/{id}` keeps returning `"filtered"` for it. Nothing about the request is lost.
* **`"filtered"` is terminal.** A filtered question never becomes `"in_progress"` or `"completed"`, so polling loops must stop on it — see [Get Question Status](/api-reference/agents/get-question-status#polling-strategy).

### What you get back to show

Both `answer` and `reason` carry the decline wording, so a client written against `answer` alone keeps working without knowing the status exists:

* **`reason`** is always the agent's own one-sentence explanation of why *this* question was declined — for example, *"This article is about a new UK immigration white paper and salary thresholds for skilled worker visas, not about statutory minimum wage rates."*
* **`answer`** is the same sentence, unless the agent's owner has written fixed wording to use instead. Doing so trades the per-question detail for a string you can rely on being identical every time.

Both are written for a person, so either is safe to log or show to whoever submitted the question. Neither is a stable identifier: the generated wording differs per question, and the fixed wording can be edited at any time. Branch on `status`, never on this text.

<Note>
  `answer` and `reason` can both be `null` on a `"filtered"` response. Questions filtered before these fields existed have no stored explanation, and one is not reconstructed on later polls. Show the explanation when it is there and fall back to your own copy when it is not.
</Note>

Editing the agent's wording only affects questions filtered afterwards. Whatever a question was answered with is stored when it is declined, so re-polling an old `id` always returns what you were originally told.

Only a **new** question is judged. A follow-up sent with `session_id` continues a conversation the agent already accepted and is never filtered.

If you supplied a `callback_url`, a `"filtered"` webhook is delivered too, so webhook-driven integrations are not left waiting for a run that will never happen.

<Note>
  An agent only accepts questions while its **API intake** is switched on. If it has been switched off, this endpoint returns `404` — the agent also stops appearing in [List Agents](/api-reference/agents/list-agents). Questions asked before it was switched off remain pollable via [Get Question Status](/api-reference/agents/get-question-status), so an in-flight answer is never stranded.
</Note>

## Async Processing & Webhooks

When using `sync_mode: false`, you can receive notifications via webhook when processing completes:

<CodeGroup>
  ```json Webhook Payload - Completed theme={null}
  {
    "id": "987fcdeb-51a2-43d1-9e8f-7b6c5a4d3e2f",
    "session_id": "987fcdeb-51a2-43d1-9e8f-7b6c5a4d3e2f",
    "session_url": "https://app.wordsmith.ai/chat/987fcdeb-51a2-43d1-9e8f-7b6c5a4d3e2f",
    "status": "completed",
    "answer": "Based on my analysis of the contract...",
    "attachments": [
      {
        "file_name": "contract_review.pdf",
        "content_type": "application/pdf",
        "content_length": 524288,
        "url": "https://files.wordsmith.ai/signed-url-here"
      }
    ],
    "reason": null
  }
  ```

  ```json Webhook Payload - Error theme={null}
  {
    "id": "987fcdeb-51a2-43d1-9e8f-7b6c5a4d3e2f",
    "session_id": "987fcdeb-51a2-43d1-9e8f-7b6c5a4d3e2f",
    "session_url": "https://app.wordsmith.ai/chat/987fcdeb-51a2-43d1-9e8f-7b6c5a4d3e2f",
    "status": "error",
    "answer": "The document format is not supported. Please convert to PDF and try again.",
    "attachments": null,
    "reason": null
  }
  ```

  ```json Webhook Payload - Filtered theme={null}
  {
    "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
    "session_id": null,
    "session_url": null,
    "status": "filtered",
    "answer": "This agent only handles commercial contract questions, and this one is about employment law.",
    "attachments": null,
    "reason": "This agent only handles commercial contract questions, and this one is about employment law."
  }
  ```
</CodeGroup>

For detailed information about webhook setup, signature verification, and security best practices, see the [Webhooks documentation](/webhooks).

## Error Responses

See the [Errors](/errors) page for the full error format reference and handling guidance.

<ResponseExample>
  ```json 400 Bad Request - Invalid Body theme={null}
  {
    "error_code": "invalid_request_body",
    "ws_api_error_code": "invalid_request_body",
    "message": "Request body is invalid. Ensure it is valid JSON with a 'question' field."
  }
  ```

  ```json 400 Bad Request - Invalid Upload Job theme={null}
  {
    "error_code": "invalid_upload_job",
    "ws_api_error_code": "invalid_upload_job",
    "message": "One or more upload_job_id values are invalid or have expired. Generate a new upload URL and re-upload the file."
  }
  ```

  ```json 400 Bad Request - Session Processing theme={null}
  {
    "error_code": "session_still_processing",
    "ws_api_error_code": "session_still_processing",
    "message": "Cannot add a new question while a previous question in this session is still processing."
  }
  ```

  ```json 401 Unauthorized theme={null}
  {
    "error_code": "unauthorized",
    "ws_api_error_code": "unauthorized",
    "message": "Invalid API key"
  }
  ```

  ```json 404 Not Found theme={null}
  {
    "error_code": "resource_not_found",
    "ws_api_error_code": "resource_not_found",
    "message": "Question not found for this agent."
  }
  ```

  ```json 404 Not Found - Agent Not Exposed theme={null}
  {
    "error_code": "resource_not_found",
    "ws_api_error_code": "resource_not_found",
    "message": "Agent 'a1b2c3d4' is not available over the API. Enable the agent's API intake to expose it."
  }
  ```

  ```json 429 Too Many Requests theme={null}
  {
    "error_code": "rate_limit_exceeded",
    "ws_api_error_code": "rate_limit_exceeded",
    "message": "Rate limit exceeded. Please retry after a short delay."
  }
  ```
</ResponseExample>

## Session Management

### Adding Questions to Existing Sessions

When adding questions to an existing session using the `session_id` parameter:

* **Conversation Context**: The agent maintains context from previous questions and answers in the session
* **Sequential Processing**: New questions cannot be submitted until the previous question in the session has completed processing
* **Error Handling**: If a previous question is still processing, the API will return a 400 Bad Request error

### ID vs Session ID

The response includes two important identifiers:

* **`id`**: The unique identifier for this specific question. For new sessions, this equals the session\_id. For follow-up questions, this is a unique question ID. For a [filtered](#filtered-questions) question it is an identifier of its own, naming a question no session was created for.
* **`session_id`**: The session ID that contains this question. This remains constant for all questions within the same conversation, and is `null` when `status` is `"filtered"`.

Use the `id` field to check the status of individual questions, and the `session_id` to identify which conversation session the question belongs to. Treat `id` as an opaque string: it is always present and always pollable, but do not assume it equals the `session_id` — that only holds for the first question of an accepted session.

## Best Practices

### Sync vs Async Mode

**Use Sync Mode (`sync_mode: true`) for:**

* Testing and development

**Use Async Mode (`sync_mode: false`) for:**

* Complex document analysis
* Multiple file attachments
* Production applications
* Long-form research questions

### File Attachments

* **Supported formats**: PDF, DOC, DOCX, TXT, MD, HTML, XLS, XLSX, CSV, TSV, PPT, PPTX, PNG, JPEG, WebP, TIFF, MP3, MP4, M4A, MPEG, WAV, WebM, ZIP
* **Maximum file size**: 50 MB per file
* **Maximum attachments**: 10 files per question

### Question Guidelines

* **Be specific**: More detailed questions get better answers
* **Provide context**: Include relevant background information

## Use Cases

### 1. Document Review & Analysis

* **Basic Review**: "Review attached document"
* **Review with Specific Playbook**: "Review this document using the Standard NDA playbook"
* **Reference Playbook by ID**: "Review this document using playbook ID: 123e4567-e89b-12d3-a456-426614174000"

### 2. Template Filling & Document Generation

* **Fill Template**: "Fill in our standardemployment agreement template using me as the employer party"
* **Reference Template by ID**: "Fill in template ID: 123e4567-e89b-12d3-a456-426614174000 using my company information"

### 3. Legal Research & Analysis

* **Case Law Research**: "What are the recent precedents for breach of contract cases in California?"
* **Regulatory Compliance**: "What are the current requirements for data protection in healthcare contracts?"
* **Legal Framework**: "Explain the key elements of a valid employment contract under UK law"
* **Industry Standards**: "What are the standard terms typically included in SaaS vendor agreements?"

### 4. Document Drafting & Creation

* **Email Drafting**: "Draft a professional email to a client explaining contract delays"
* **Clause Drafting**: "Draft a force majeure clause for a construction contract"
* **Legal Letters**: "Write a demand letter for unpaid invoices"
* **Meeting Minutes**: "Draft meeting minutes based on the attached audio recording"

### 5. Translation & Conversion

* **Language Translation**: "Translate this contract to Spanish while maintaining legal accuracy"
* **Multi-language**: "Provide this agreement in both English and French versions"
* **Format Conversion**: "Convert this PDF document to DOCX"

### 6. Presentations & Spreadsheets

* **Generate Presentation**: "Create a PowerPoint presentation summarizing the key findings from the review of attached NDA"
* **Executive Summary**: "Generate an executive summary of this legal document for senior management"
* **Questionnaire Processing**: "Fill in this security questionnaire in the attached XLSX"
* **Spreadsheet Generation**: "Extract all dates, amounts, and party names from this document into a structured spreadsheet"
