Skip to main content

Overview

Submit security questionnaires and RFPs to Wolfia for AI-powered autofilling, then track their processing status and retrieve results programmatically.

Upload a file

URL: POST https://api.wolfia.com/v1/questionnaire/upload/file Authentication: API key required (see API overview for setup) This endpoint accepts multipart form data.
curl -X POST https://api.wolfia.com/v1/questionnaire/upload/file \
  -H "X-API-Key: wolfia-api-YOUR_KEY_HERE" \
  -F "file=@questionnaire.xlsx;type=application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" \
  -F "company_name=Acme Corp" \
  -F "deal_value=50000" \
  -F "deadline=2025-03-15" \
  -F "instructions=Focus on SOC 2 and ISO 27001 compliance"
You must set the correct MIME type for the file using the ;type= syntax in curl (or the equivalent Content-Type in your HTTP client). Uploads with an incorrect MIME type will fail to process.

Request parameters

ParameterTypeRequiredDescription
filefileYesThe questionnaire file
company_namestringYesCompany that sent the questionnaire
deal_valuedecimalNoAssociated deal value
deadlinedate (YYYY-MM-DD)NoCompletion deadline
instructionsstringNoInstructions to guide AI processing
tag_idsarray of stringsNoTag IDs to categorize the questionnaire (see Content tags)
assignee_idsarray of stringsNoUser IDs to assign to
assignee_typesarray of stringsNoType per assignee (USER or GROUP)

Supported file types

ExtensionMIME type
.xlsxapplication/vnd.openxmlformats-officedocument.spreadsheetml.sheet
.xlsmapplication/vnd.ms-excel.sheet.macroenabled.12
.xlsapplication/vnd.ms-excel
.csvtext/csv
.docxapplication/vnd.openxmlformats-officedocument.wordprocessingml.document
.pdfapplication/pdf

Response (200 OK)

{
  "questionnaire_id": "da891171-9293-4218-a74a-c53c55673beb",
  "message": "File 'questionnaire.xlsx' uploaded successfully and queued for processing"
}

Upload text content

URL: POST https://api.wolfia.com/v1/questionnaire/upload/text Authentication: API key required (see API overview for setup) Use this when you have questions as text rather than a file — for example, pasted from an email or extracted from a web form.
curl -X POST https://api.wolfia.com/v1/questionnaire/upload/text \
  -H "X-API-Key: wolfia-api-YOUR_KEY_HERE" \
  -H "Content-Type: application/json" \
  -d '{
    "text_content": "1. Describe your data encryption standards.\n2. How do you handle incident response?\n3. What certifications do you hold?",
    "company_name": "Acme Corp"
  }'

Request parameters

ParameterTypeRequiredDescription
text_contentstringYesQuestions as text (50 to 200,000 characters)
company_namestringNoCompany that sent the questionnaire
source_typestringNoDefaults to TEXT
deal_valuedecimalNoAssociated deal value
deadlinedate (YYYY-MM-DD)NoCompletion deadline
instructionsstringNoInstructions to guide AI processing
tag_idsarray of stringsNoTag IDs to categorize the questionnaire (see Content tags)
assigneesarray of objectsNoEach with id (string) and type (USER or GROUP)

Response (200 OK)

{
  "questionnaire_id": "da891171-9293-4218-a74a-c53c55673beb",
  "message": "Text content uploaded successfully and queued for processing"
}

List questionnaires

URL: GET https://api.wolfia.com/v1/questionnaire/list Authentication: API key required Returns a paginated list of all questionnaires in your organization, ordered by creation date (newest first).

Request

curl -X GET 'https://api.wolfia.com/v1/questionnaire/list?limit=20&offset=0' \
  -H "X-API-Key: wolfia-api-YOUR_KEY_HERE"

Query parameters

ParameterTypeRequiredDefaultDescription
limitinteger (1-1000)No10Number of questionnaires to return
offsetintegerNo0Number of questionnaires to skip (for pagination)

Response (200 OK)

{
  "questionnaires": [
    {
      "id": "da891171-9293-4218-a74a-c53c55673beb",
      "title": "SOC 2 Security Questionnaire",
      "company_name": "Acme Corp",
      "status": "ANSWERING_COMPLETED",
      "status_display_name": "Ready for review",
      "total_questions": 150,
      "answered_questions": 148,
      "created_at": 1735689600000000,
      "deadline": "2025-03-15",
      "deal_value": 50000,
      "tags": [
        {
          "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
          "name": "SOC 2",
          "description": "SOC 2 compliance questionnaires",
          "is_ai_generated": false,
          "status": "ACTIVE"
        }
      ],
      "should_poll": false
    }
  ],
  "pagination": {
    "total": 42,
    "limit": 20,
    "offset": 0
  },
  "should_poll": false
}
The should_poll field (at both the list level and individual questionnaire level) indicates whether any questionnaires are still being processed. If true, poll the endpoint periodically to get updated statuses.

Processing status values

After uploading, a questionnaire moves through these statuses:
StatusDisplay nameMeaning
UPLOADEDUploadedFile received, processing not started
QUEUED_PENDING_REVIEWPre-validationQueued for initial validation before processing
QUEUED_FOR_EXTRACTIONQueuedValidated and queued for question extraction
ANALYSIS_IN_PROGRESSAnalyzingAI is analyzing the document structure
QUESTION_EXTRACTION_IN_PROGRESSExtractingAI is extracting individual questions
ANSWERING_IN_PROGRESSAnsweringAI is generating answers
ANSWERING_COMPLETEDReady for reviewAll answers generated, ready for human review
READY_FOR_APPROVALReady for approvalReviewed and pending final approval
COMPLETEDCompletedFully completed
Failed statuses (ANALYSIS_FAILED, QUESTION_EXTRACTION_FAILED, ANSWERING_FAILED) indicate a processing error. Contact support@wolfia.com if failures persist.

Search questionnaires

URL: GET https://api.wolfia.com/v1/questionnaire/search Authentication: API key required Search questionnaires by text or filter by specific fields using the @field:value syntax.

Request

# Text search
curl -X GET 'https://api.wolfia.com/v1/questionnaire/search?query=security+review' \
  -H "X-API-Key: wolfia-api-YOUR_KEY_HERE"

# Filter by status
curl -X GET 'https://api.wolfia.com/v1/questionnaire/search?query=@status:ANSWERING_COMPLETED' \
  -H "X-API-Key: wolfia-api-YOUR_KEY_HERE"

# Filter by account name
curl -X GET 'https://api.wolfia.com/v1/questionnaire/search?query=@account:Acme' \
  -H "X-API-Key: wolfia-api-YOUR_KEY_HERE"

# Combine filters
curl -X GET 'https://api.wolfia.com/v1/questionnaire/search?query=@status:ANSWERING_IN_PROGRESS+@account:Acme' \
  -H "X-API-Key: wolfia-api-YOUR_KEY_HERE"

Query parameters

ParameterTypeRequiredDefaultDescription
querystringNo""Search query (see filter syntax below)
limitinteger (1-1000)No10Number of results to return
offsetintegerNo0Pagination offset

Filter syntax

Use @field:value to filter by specific fields. Multiple filters can be combined in a single query.
FilterExampleDescription
@title:@title:security reviewMatch questionnaire title
@status:@status:ANSWERING_COMPLETEDMatch processing status (see status values)
@account:@account:AcmeMatch company name
Plain text without the @ prefix searches across all fields.

Response (200 OK)

The response format matches List questionnaires, with an additional matched_questions array on each item showing which questions matched the search query.

Get questionnaire details

URL: GET https://api.wolfia.com/v1/questionnaire/{questionnaire_id}/overview Authentication: API key required Returns detailed information about a specific questionnaire, including per-sheet statistics, processing logs, and completion metrics.

Request

curl -X GET 'https://api.wolfia.com/v1/questionnaire/da891171-9293-4218-a74a-c53c55673beb/overview' \
  -H "X-API-Key: wolfia-api-YOUR_KEY_HERE"

Response (200 OK)

{
  "id": "da891171-9293-4218-a74a-c53c55673beb",
  "title": "SOC 2 Security Questionnaire",
  "company_name": "Acme Corp",
  "status": "ANSWERING_COMPLETED",
  "status_display_name": "Ready for review",
  "total_questions": 150,
  "answered_questions": 148,
  "statistics": {
    "total_questions": 150,
    "answered_questions": 148,
    "approved_questions": 0,
    "ai_answered_questions": 145,
    "manual_answered_questions": 3,
    "not_answered_questions": 2,
    "completion_percentage": 98.67,
    "approval_percentage": 0.0
  },
  "created_at": 1735689600000000,
  "deadline": "2025-03-15",
  "deal_value": 50000,
  "tags": [
    {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "name": "SOC 2",
      "description": "SOC 2 compliance questionnaires",
      "is_ai_generated": false,
      "status": "ACTIVE"
    }
  ],
  "sheets": [
    {
      "id": "sheet-uuid",
      "name": "Security Controls",
      "status": "ANSWERING_COMPLETED",
      "should_poll": false
    }
  ],
  "sheet_stats": [
    {
      "id": "sheet-uuid",
      "name": "Security Controls",
      "status": "ANSWERING_COMPLETED",
      "total_questions": 150,
      "answered_questions": 148,
      "completion_percentage": 98.67
    }
  ],
  "should_poll": false
}
Use should_poll to determine if the questionnaire is still being processed. If true, poll this endpoint at reasonable intervals (e.g., every 10-30 seconds) until processing completes.

Key response fields

FieldTypeDescription
idstring (UUID)Questionnaire identifier
statusstringCurrent processing status (see status values)
status_display_namestringHuman-readable status
total_questionsintegerTotal extracted questions
answered_questionsintegerQuestions with AI or manual answers
statisticsobjectDetailed completion and quality metrics
sheetsarrayIndividual sheets/tabs with their processing status
sheet_statsarrayPer-sheet question and completion statistics
tagsarrayContent tags applied to this questionnaire
should_pollbooleantrue if processing is still in progress
created_atintegerCreation timestamp (microseconds)

Integration example

Python: Upload and poll until complete

import os
import time

import requests

API_KEY = os.environ['WOLFIA_API_KEY']
BASE_URL = 'https://api.wolfia.com/v1'


def upload_and_wait(file_path, company_name, timeout_seconds=600):
    """Upload a questionnaire and poll until processing completes."""
    headers = {'X-API-Key': API_KEY}

    # Upload the file
    with open(file_path, 'rb') as f:
        resp = requests.post(
            f'{BASE_URL}/questionnaire/upload/file',
            headers=headers,
            files={'file': (os.path.basename(file_path), f, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')},
            data={'company_name': company_name},
            timeout=60,
        )
    resp.raise_for_status()
    qid = resp.json()['questionnaire_id']
    print(f'Uploaded: {qid}')

    # Poll for completion
    start = time.time()
    while time.time() - start < timeout_seconds:
        overview = requests.get(
            f'{BASE_URL}/questionnaire/{qid}/overview',
            headers=headers,
            timeout=30,
        )
        overview.raise_for_status()
        data = overview.json()

        status = data['status']
        display = data['status_display_name']
        print(f'  Status: {display} ({status})')

        if not data['should_poll']:
            return data

        time.sleep(15)

    raise TimeoutError(f'Questionnaire {qid} did not complete within {timeout_seconds}s')


if __name__ == '__main__':
    result = upload_and_wait('questionnaire.xlsx', 'Acme Corp')
    stats = result['statistics']
    print(f"Done: {stats['answered_questions']}/{stats['total_questions']} answered ({stats['completion_percentage']:.1f}%)")

Python: Ingest questionnaires from JIRA

import mimetypes
import os

import requests
from jira import JIRA

WOLFIA_API_KEY = os.environ["WOLFIA_API_KEY"]
BASE_URL = "https://api.wolfia.com/v1"

MIME_TYPES = {
    ".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
    ".xlsm": "application/vnd.ms-excel.sheet.macroenabled.12",
    ".xls": "application/vnd.ms-excel",
    ".csv": "text/csv",
    ".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
    ".pdf": "application/pdf",
}


def get_mime_type(filename):
    ext = os.path.splitext(filename)[1].lower()
    return MIME_TYPES.get(ext, mimetypes.guess_type(filename)[0])


def process_questionnaire_tickets():
    jira = JIRA(server=os.environ["JIRA_SERVER"], token_auth=os.environ["JIRA_TOKEN"])
    issues = jira.search_issues('project = SEC AND type = "Security Questionnaire" AND status = "To Do"', maxResults=50)

    for issue in issues:
        company = issue.fields.summary.split(" - ")[0] if " - " in issue.fields.summary else issue.fields.summary

        if issue.fields.attachment:
            att = issue.fields.attachment[0]
            mime_type = get_mime_type(att.filename)
            resp = requests.post(
                f"{BASE_URL}/questionnaire/upload/file",
                headers={"X-API-Key": WOLFIA_API_KEY},
                files={"file": (att.filename, att.get(), mime_type)},
                data={"company_name": company, "instructions": issue.fields.description or ""},
                timeout=60,
            )
        elif issue.fields.description and len(issue.fields.description) >= 50:
            resp = requests.post(
                f"{BASE_URL}/questionnaire/upload/text",
                headers={"X-API-Key": WOLFIA_API_KEY, "Content-Type": "application/json"},
                json={"text_content": issue.fields.description, "company_name": company},
                timeout=30,
            )
        else:
            print(f"Skipping {issue.key}: no attachment or usable description")
            continue

        if resp.status_code == 200:
            qid = resp.json()["questionnaire_id"]
            jira.add_comment(issue, f"Uploaded to Wolfia (ID: {qid})")
            jira.transition_issue(issue, "In Progress")
            print(f"  {issue.key} -> {qid}")
        else:
            print(f"  {issue.key} failed: {resp.text}")


if __name__ == "__main__":
    process_questionnaire_tickets()

Error responses

Status CodeWhat it meansHow to fix
400Unsupported file typeUse a supported format: .xlsx, .xlsm, .xls, .csv, .docx, .pdf
401Invalid or expired API keyVerify your API key
403Insufficient permissionsCheck the API key owner’s role
404Questionnaire not foundVerify the questionnaire ID exists
422Missing required fields or invalid inputCheck required fields. Text must be 50-200,000 characters.
500Internal errorRetry with exponential backoff

Best practices

Use file upload when you have the original document (XLSX, PDF, DOCX). Wolfia preserves the document structure.Use text upload for plain text questions from emails, web forms, or chat messages.
The instructions field shapes how Wolfia fills in answers:
{
  "instructions": "This is a SOC 2 questionnaire. Reference our latest audit report."
}
Include company_name, deal_value, and deadline when available. This metadata appears in the Wolfia dashboard for prioritization.
After uploading, use the get questionnaire details endpoint to track progress. Check the should_poll field — when it’s false, processing is complete. A polling interval of 15-30 seconds is recommended.

Getting help

  • Check file types: .xlsx, .xlsm, .xls, .csv, .docx, .pdf
  • Check text length: 50 to 200,000 characters
  • Contact support: Email support@wolfia.com

Next steps