curl --request POST \
--url https://api.example.com/api/proposals/{proposal_id}/analyze-rfp{
"status": "<string>",
"message": "<string>",
"started_at": "<string>",
"cached": true,
"rfp_analysis": {},
"completed_at": "<string>",
"error": "<string>"
}curl --request POST \
--url https://api.example.com/api/proposals/{proposal_id}/analyze-rfp{
"status": "<string>",
"message": "<string>",
"started_at": "<string>",
"cached": true,
"rfp_analysis": {},
"completed_at": "<string>",
"error": "<string>"
}Documentation Index
Fetch the complete documentation index at: https://mintlify.com/AllianceBioversityCIAT/alliance-IGAD/llms.txt
Use this file to discover all available pages before exploring further.
/analyze-rfp returns immediately with status: "processing"AnalysisWorkerFunction with InvocationType: "Event"/analysis-status every 3 seconds"completed" with analysis resultsPROP-YYYYMMDD-XXXX)processing: Analysis started successfullycompleted: Analysis already exists (cached)true if returning cached results (no re-analysis)curl -X POST "https://api.igad-innovation.org/api/proposals/PROP-20260304-A1B2/analyze-rfp" \
-H "Authorization: Bearer YOUR_TOKEN"
{
"status": "processing",
"message": "RFP analysis started. Poll /analysis-status for completion.",
"started_at": "2026-03-04T10:30:00.000Z"
}
{
"status": "completed",
"rfp_analysis": {
"semantic_query": "Build a digital platform for farmer cooperatives...",
"key_requirements": [...],
"evaluation_criteria": [...]
},
"message": "RFP already analyzed",
"cached": true
}
analysis_status_rfp field in DynamoDB tracks the analysis state:
| Status | Description |
|---|---|
not_started | No analysis has been triggered |
processing | Lambda worker is analyzing the RFP |
completed | Analysis finished successfully |
failed | Analysis encountered an error |
const pollStatus = async (proposalId: string) => {
const interval = setInterval(async () => {
const response = await fetch(
`/api/proposals/${proposalId}/analysis-status`,
{ headers: { Authorization: `Bearer ${token}` } }
)
const data = await response.json()
if (data.status === 'completed') {
clearInterval(interval)
console.log('Analysis complete:', data.rfp_analysis)
} else if (data.status === 'failed') {
clearInterval(interval)
console.error('Analysis failed:', data.error)
}
}, 3000) // Poll every 3 seconds
}
worker_function_arn = os.environ.get("WORKER_FUNCTION_NAME")
# Example: "arn:aws:lambda:us-east-1:123456789012:function:AnalysisWorkerFunction"
lambda_client.invoke(
FunctionName=worker_function_arn,
InvocationType="Event", # Async invocation (non-blocking)
Payload=json.dumps({
"proposal_id": proposal_code, # Uses PROP-YYYYMMDD-XXXX format
"analysis_type": "rfp"
})
)
await db_client.update_item(
pk=f"PROPOSAL#{proposal_code}",
sk="METADATA",
update_expression="SET analysis_status_rfp = :status, rfp_analysis_started_at = :started",
expression_attribute_values={
":status": "processing",
":started": datetime.utcnow().isoformat()
}
)
db_client.update_item_sync(
pk=f"PROPOSAL#{proposal_code}",
sk="METADATA",
update_expression="SET analysis_status_rfp = :status, rfp_analysis = :result, rfp_analysis_completed_at = :completed",
expression_attribute_values={
":status": "completed",
":result": analysis_result,
":completed": datetime.utcnow().isoformat()
}
)
rfp_analysis already exists in DynamoDB, the endpoint returns cached data immediately without triggering a new analysis.{
"detail": "Proposal code not found"
}
{
"detail": "Access denied"
}
{
"detail": "Proposal not found"
}
{
"detail": "RFP analysis failed: WORKER_FUNCTION_NAME environment variable not set"
}
not_started, processing, completed, or failedcompleted){
"status": "completed",
"rfp_analysis": {
"semantic_query": "Develop a digital platform for agricultural cooperatives in the IGAD region...",
"key_requirements": [
"Mobile-first design",
"Offline functionality",
"Multi-language support"
],
"evaluation_criteria": [
{
"criterion": "Technical Approach",
"weight": "30%",
"description": "Quality and feasibility of proposed solution"
}
],
"budget_range": "$50,000 - $100,000",
"timeline": "12 months"
},
"completed_at": "2026-03-04T10:32:45.000Z"
}
{
"status": "processing",
"started_at": "2026-03-04T10:30:00.000Z"
}
{
"status": "failed",
"error": "Failed to extract text from RFP document"
}