Skip to main content
POST
/
api
/
proposals
/
{proposal_id}
/
generate-concept-document
Generate Concept Document
curl --request POST \
  --url https://api.example.com/api/proposals/{proposal_id}/generate-concept-document \
  --header 'Content-Type: application/json' \
  --data '
{
  "concept_evaluation": {
    "concept_analysis": {},
    "status": "<string>"
  }
}
'
{
  "status": "<string>",
  "message": "<string>",
  "started_at": "<string>",
  "completed_at": "<string>",
  "concept_document": "<string>",
  "error": "<string>"
}

Overview

Generates an enhanced concept document based on RFP analysis and user’s concept evaluation. This endpoint takes the sections identified in concept analysis and creates a comprehensive, AI-enhanced version of the concept document.
Prerequisites:
  • RFP analysis must be completed
  • Concept analysis must be completed
  • User must have selected/evaluated sections (via /concept-evaluation endpoint)

Workflow Pattern

Follows the asynchronous Lambda worker pattern:
  1. Trigger: POST to /generate-concept-document starts generation
  2. Validation: Backend validates required data exists in DynamoDB
  3. Lambda Worker: Invokes worker with analysis_type: "concept_document"
  4. Polling: Poll GET /concept-document-status for completion
  5. Result: Returns enhanced concept document in markdown format

Request

proposal_id
string
required
The proposal ID or code (format: PROP-YYYYMMDD-XXXX)
concept_evaluation
object
required
User’s evaluation of concept analysis sections. This is typically populated by the frontend after the user reviews the concept analysis.
Important: The backend uses the concept_analysis data stored in DynamoDB (which includes user selections from the /concept-evaluation endpoint), NOT the concept_evaluation parameter. The parameter acts as a trigger, but the source of truth is DynamoDB.

Response

status
string
  • processing: Document generation started
message
string
Instruction to poll the status endpoint

Example Request

curl -X POST "https://api.igad-innovation.org/api/proposals/PROP-20260304-A1B2/generate-concept-document" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "concept_evaluation": {
      "concept_analysis": {
        "sections_needing_elaboration": [
          {
            "title": "Technical Architecture",
            "selected": true
          }
        ]
      },
      "status": "completed"
    }
  }'

Example Response

{
  "status": "processing",
  "message": "Concept document generation started. Poll /concept-document-status for updates."
}

User Selection Workflow

Before generating the concept document, users should review and select sections:

Step 1: Update Concept Evaluation

// Save user's section selections
const response = await fetch(
  `/api/proposals/${proposalId}/concept-evaluation`,
  {
    method: 'PUT',
    headers: {
      'Authorization': `Bearer ${token}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      selected_sections: [
        { title: 'Technical Architecture', selected: true },
        { title: 'Methodology', selected: true },
        { title: 'Risk Management', selected: false }
      ],
      user_comments: {
        'Technical Architecture': 'Please emphasize scalability'
      }
    })
  }
)

Step 2: Generate Document

// Trigger document generation
const response = await fetch(
  `/api/proposals/${proposalId}/generate-concept-document`,
  {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${token}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      concept_evaluation: { status: 'completed' }
    })
  }
)

Step 3: Poll Status

const pollStatus = async () => {
  const interval = setInterval(async () => {
    const response = await fetch(
      `/api/proposals/${proposalId}/concept-document-status`,
      { headers: { Authorization: `Bearer ${token}` } }
    )
    const data = await response.json()

    if (data.status === 'completed') {
      clearInterval(interval)
      displayConceptDocument(data.concept_document)
    }
  }, 3000)
}

Lambda Worker Details

Environment Variables

worker_function = os.getenv("WORKER_FUNCTION_NAME")

Lambda Invocation Payload

payload = {
    "analysis_type": "concept_document",
    "proposal_id": proposal_code,  # PROP-YYYYMMDD-XXXX format
    "user_id": user_id,
    "concept_evaluation": final_concept_evaluation  # From DynamoDB with selections
}

lambda_client.invoke(
    FunctionName=worker_function,
    InvocationType="Event",  # Asynchronous
    Payload=json.dumps(payload)
)

DynamoDB Updates

Before invocation:
await db_client.update_item(
    pk=proposal["PK"],
    sk=proposal["SK"],
    update_expression="SET concept_document_status = :status, concept_document_started_at = :started",
    expression_attribute_values={
        ":status": "processing",
        ":started": datetime.utcnow().isoformat()
    }
)
After completion (in worker):
db_client.update_item_sync(
    pk=pk,
    sk="METADATA",
    update_expression="SET concept_document_status = :status, concept_document_v2 = :doc, concept_document_completed_at = :completed",
    expression_attribute_values={
        ":status": "completed",
        ":doc": generated_document,
        ":completed": datetime.utcnow().isoformat()
    }
)

Status Values

The concept_document_status field tracks generation progress:
StatusDescription
not_startedNo generation triggered
processingLambda worker is generating document
completedDocument generated successfully
failedGeneration encountered an error

Polling for Status

GET /api/proposals/{proposal_id}/concept-document-status

Check concept document generation status

Error Handling

Status Code 400 - Missing RFP Analysis

{
  "detail": "RFP analysis not found. Complete Step 1 first."
}

Status Code 400 - Missing Concept Analysis

{
  "detail": "Concept analysis not found. Complete Step 1 first."
}

Status Code 400 - Missing Proposal Code

{
  "detail": "Proposal code not found"
}

Status Code 404

{
  "detail": "Proposal not found"
}

Status Code 500

{
  "detail": "Worker lambda invocation failed"
}

GET Concept Document Status

Description

Poll this endpoint to check concept document generation status.

Request

proposal_id
string
required
The proposal ID or code

Response

status
string
Current status: not_started, processing, completed, or failed
started_at
string
ISO timestamp when generation started
completed_at
string
ISO timestamp when generation completed
concept_document
string
Generated concept document in markdown format (only when completed)
error
string
Error message (only when failed)

Example Response (Completed)

{
  "status": "completed",
  "started_at": "2026-03-04T10:40:00.000Z",
  "completed_at": "2026-03-04T10:42:15.000Z",
  "concept_document": "# Enhanced Concept Document\n\n## Executive Summary\n\nThis proposal aims to develop a comprehensive digital platform...\n\n## Technical Architecture\n\n### System Design\n\nThe platform will be built using a microservices architecture...\n\n### Scalability Considerations\n\nTo handle expected growth...\n\n## Methodology\n\n### Development Approach\n\nWe will employ Agile methodology with 2-week sprints..."
}

Example Response (Processing)

{
  "status": "processing",
  "started_at": "2026-03-04T10:40:00.000Z",
  "completed_at": null
}

Example Response (Failed)

{
  "status": "failed",
  "started_at": "2026-03-04T10:40:00.000Z",
  "error": "AI service temporarily unavailable"
}

Document Format

The generated concept document is returned as markdown with:
  • Hierarchical structure: Using #, ##, ### headers
  • Enhanced content: AI-generated elaborations for selected sections
  • Formatted lists: Bullet points and numbered lists where appropriate
  • Professional tone: Suitable for submission to funding organizations

Example Document Structure

# Enhanced Concept Document

## Executive Summary
[AI-generated summary]

## Problem Statement
[Elaborated problem context]

## Proposed Solution

### Technical Architecture
[Detailed technical description]

### Implementation Methodology
[Step-by-step approach]

## Expected Outcomes
[Measurable deliverables]

## Budget Overview
[Cost breakdown]

## Timeline
[Project schedule]

Next Steps

After the concept document is generated:
  1. User reviews the enhanced document
  2. User can download or export the document
  3. Proceed to structure and workplan analysis (Step 3)

POST /api/proposals/{proposal_id}/analyze-step-3

Generate proposal structure and workplan

Best Practices

Optimize generation time: Only select sections that truly need elaboration. Unselected sections will be excluded from AI processing, reducing generation time and cost.
Save user selections first: Always call PUT /concept-evaluation before generating the document to ensure user preferences are stored in DynamoDB.
Don’t retry immediately on failure: If status returns "failed", wait at least 30 seconds before retrying to avoid overwhelming the worker Lambda.

Build docs developers (and LLMs) love