🔌 API Reference

Complete API documentation for developers integrating with ProposalForge

Overview

The ProposalForge API allows you to programmatically create, manage, and generate proposals. Built on Cloudflare Workers with D1 database storage, our API is fast, reliable, and globally distributed.

Base URL: https://your-worker-url.workers.dev
Version: 1.0.0
Protocol: HTTPS only
Format: JSON

Authentication

Currently, the API is open and does not require authentication. Future versions will implement API key authentication for production use.

⚠️ Development Notice: This API is in active development. Breaking changes may occur. Always specify version in production integrations.

Rate Limiting

The API implements rate limiting to ensure fair usage:

Response Format

All API responses follow a consistent JSON structure:

{ "success": true, "data": { ... }, "message": "Operation successful" }

Error responses include additional details:

{ "success": false, "error": "Error message", "code": "ERROR_CODE", "details": { ... } }

Endpoints

POST /api/generate-ai

Generate a proposal using AI based on a project description.

Request Body

Parameter Type Required Description
description string Required Project description (min 20 chars, max 5000 chars)
clientName string Optional Client name to include in proposal
currency string Optional Preferred currency (default: USD)

Example Request

POST /api/generate-ai Content-Type: application/json { "description": "Build a responsive e-commerce website with product catalog, shopping cart, and Stripe integration. Timeline: 2 months.", "clientName": "Acme Corporation", "currency": "USD" }

Example Response

{ "success": true, "data": { "clientName": "Acme Corporation", "projectOverview": "Development of a comprehensive e-commerce platform...", "phases": [ { "name": "Discovery & Planning", "description": "Requirements gathering, wireframes, and project planning", "duration": "1 week", "price": 3000 }, { "name": "Frontend Development", "description": "Responsive UI with product catalog and shopping cart", "duration": "3 weeks", "price": 12000 } ], "currency": "USD", "totalPrice": 15000, "paymentTerms": "30% upfront, 40% at midpoint, 30% on completion", "deliveryTerms": "Weekly progress updates, staged deployment" }, "message": "Proposal generated successfully" }

Error Responses

// 400 Bad Request { "success": false, "error": "Description is required and must be at least 20 characters", "code": "INVALID_DESCRIPTION" } // 429 Too Many Requests { "success": false, "error": "Rate limit exceeded. Please try again in 60 seconds", "code": "RATE_LIMIT_EXCEEDED" } // 500 Internal Server Error { "success": false, "error": "AI service temporarily unavailable", "code": "AI_SERVICE_ERROR" }

POST /api/generate-pdf

Generate a professional PDF from proposal data.

Request Body

Parameter Type Required Description
clientName string Required Client name
clientCompany string Optional Client company name
clientEmail string Optional Client email address
projectOverview string Required Project description
phases array Required Array of phase objects (min 1)
currency string Required Currency code (USD, EUR, GBP, etc.)
paymentTerms string Optional Payment terms description
deliveryTerms string Optional Delivery terms description

Phase Object Structure

Property Type Required Description
name string Required Phase name
description string Required Phase description
duration string Required Duration estimate (e.g., "2 weeks")
price number Required Phase price (positive number)

Example Request

POST /api/generate-pdf Content-Type: application/json { "clientName": "John Smith", "clientCompany": "Acme Corp", "clientEmail": "john@acme.com", "projectOverview": "Development of a modern e-commerce platform", "phases": [ { "name": "Discovery & Planning", "description": "Requirements gathering and project planning", "duration": "1 week", "price": 3000 }, { "name": "Development", "description": "Full stack development of the platform", "duration": "6 weeks", "price": 18000 } ], "currency": "USD", "paymentTerms": "50% upfront, 50% on completion", "deliveryTerms": "Weekly progress updates via email" }

Example Response

{ "success": true, "data": { "pdfUrl": "data:application/pdf;base64,JVBERi0xLjcKJeLjz9...", "fileName": "proposal-20260120-143022.pdf", "fileSize": 125847, "totalPrice": 21000 }, "message": "PDF generated successfully" }

Error Responses

// 400 Bad Request - Missing required fields { "success": false, "error": "Missing required fields: clientName, projectOverview, phases", "code": "VALIDATION_ERROR" } // 400 Bad Request - Invalid phase data { "success": false, "error": "Each phase must have name, description, duration, and price", "code": "INVALID_PHASE_DATA" } // 500 Internal Server Error { "success": false, "error": "PDF generation failed", "code": "PDF_GENERATION_ERROR" }

POST /api/proposals

Save a proposal to the database for record keeping.

Request Body

Same structure as /api/generate-pdf endpoint.

Example Response

{ "success": true, "data": { "proposalId": "prop_abc123xyz", "createdAt": "2026-01-20T14:30:22Z" }, "message": "Proposal saved successfully" }

GET /api/currencies

Get list of supported currencies with formatting information.

Example Response

{ "success": true, "data": [ { "code": "USD", "name": "US Dollar", "symbol": "$", "symbolPosition": "before", "decimals": 2 }, { "code": "EUR", "name": "Euro", "symbol": "€", "symbolPosition": "before", "decimals": 2 }, { "code": "GBP", "name": "British Pound", "symbol": "£", "symbolPosition": "before", "decimals": 2 } ], "message": "Currencies retrieved successfully" }

SDK & Libraries

JavaScript/TypeScript

Example integration using fetch API:

// Generate AI Proposal async function generateProposal(description) { const response = await fetch('https://your-worker.workers.dev/api/generate-ai', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ description, currency: 'USD' }) }); const result = await response.json(); if (result.success) { return result.data; } else { throw new Error(result.error); } } // Generate PDF async function generatePDF(proposalData) { const response = await fetch('https://your-worker.workers.dev/api/generate-pdf', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(proposalData) }); const result = await response.json(); if (result.success) { // Create download link const link = document.createElement('a'); link.href = result.data.pdfUrl; link.download = result.data.fileName; link.click(); } else { throw new Error(result.error); } } // Usage const proposal = await generateProposal('Build an e-commerce website...'); await generatePDF(proposal);

Python

Example integration using requests library:

import requests import json class ProposalForge: def __init__(self, base_url): self.base_url = base_url def generate_ai_proposal(self, description, currency='USD'): """Generate proposal using AI""" url = f"{self.base_url}/api/generate-ai" payload = { "description": description, "currency": currency } response = requests.post(url, json=payload) result = response.json() if result['success']: return result['data'] else: raise Exception(result['error']) def generate_pdf(self, proposal_data): """Generate PDF from proposal data""" url = f"{self.base_url}/api/generate-pdf" response = requests.post(url, json=proposal_data) result = response.json() if result['success']: # Save PDF to file pdf_data = result['data']['pdfUrl'].split(',')[1] with open(result['data']['fileName'], 'wb') as f: f.write(base64.b64decode(pdf_data)) return result['data']['fileName'] else: raise Exception(result['error']) # Usage client = ProposalForge('https://your-worker.workers.dev') proposal = client.generate_ai_proposal('Build an e-commerce website...') pdf_file = client.generate_pdf(proposal) print(f"PDF saved to: {pdf_file}")

PHP

Example integration using cURL:

<?php class ProposalForge { private $baseUrl; public function __construct($baseUrl) { $this->baseUrl = $baseUrl; } public function generateAIProposal($description, $currency = 'USD') { $url = $this->baseUrl . '/api/generate-ai'; $data = [ 'description' => $description, 'currency' => $currency ]; $ch = curl_init($url); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); curl_close($ch); $result = json_decode($response, true); if ($result['success']) { return $result['data']; } else { throw new Exception($result['error']); } } public function generatePDF($proposalData) { $url = $this->baseUrl . '/api/generate-pdf'; $ch = curl_init($url); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($proposalData)); curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); curl_close($ch); $result = json_decode($response, true); if ($result['success']) { return $result['data']; } else { throw new Exception($result['error']); } } } // Usage $client = new ProposalForge('https://your-worker.workers.dev'); $proposal = $client->generateAIProposal('Build an e-commerce website...'); $pdf = $client->generatePDF($proposal); echo "PDF generated: " . $pdf['fileName']; ?>

Webhooks

Webhooks are planned for future releases and will allow you to receive real-time notifications for events such as:

Coming Soon: Webhook support is currently in development. Subscribe to our newsletter to be notified when webhooks become available.

Error Codes

Code HTTP Status Description
INVALID_DESCRIPTION 400 Description is missing or too short/long
VALIDATION_ERROR 400 Required fields are missing or invalid
INVALID_PHASE_DATA 400 Phase objects are missing required fields
INVALID_CURRENCY 400 Currency code not supported
RATE_LIMIT_EXCEEDED 429 Too many requests from this IP
AI_SERVICE_ERROR 500 Anthropic API error or timeout
PDF_GENERATION_ERROR 500 PDF creation failed
DATABASE_ERROR 500 Database operation failed
INTERNAL_ERROR 500 Unexpected server error

Best Practices

Error Handling

Always implement proper error handling in your integrations:

try { const proposal = await generateProposal(description); const pdf = await generatePDF(proposal); } catch (error) { if (error.code === 'RATE_LIMIT_EXCEEDED') { // Wait and retry await new Promise(resolve => setTimeout(resolve, 60000)); return generateProposal(description); } else if (error.code === 'AI_SERVICE_ERROR') { // Fallback to manual creation showManualForm(); } else { // Show error to user showError(error.message); } }

Rate Limit Handling

Implement exponential backoff for rate limit errors:

async function retryWithBackoff(fn, maxRetries = 3) { for (let i = 0; i < maxRetries; i++) { try { return await fn(); } catch (error) { if (error.code === 'RATE_LIMIT_EXCEEDED' && i < maxRetries - 1) { const delay = Math.pow(2, i) * 1000; await new Promise(resolve => setTimeout(resolve, delay)); } else { throw error; } } } }

Caching

Cache currency list and other static data to reduce API calls:

let currencyCache = null; let cacheExpiry = null; async function getCurrencies() { const now = Date.now(); if (currencyCache && cacheExpiry && now < cacheExpiry) { return currencyCache; } const response = await fetch('/api/currencies'); const result = await response.json(); currencyCache = result.data; cacheExpiry = now + 3600000; // 1 hour return currencyCache; }

Validation

Validate data client-side before sending to the API:

function validateProposal(data) { const errors = []; if (!data.clientName || data.clientName.length < 2) { errors.push('Client name must be at least 2 characters'); } if (!data.projectOverview || data.projectOverview.length < 20) { errors.push('Project overview must be at least 20 characters'); } if (!data.phases || data.phases.length === 0) { errors.push('At least one phase is required'); } data.phases?.forEach((phase, index) => { if (!phase.name) errors.push(`Phase ${index + 1}: Name is required`); if (!phase.price || phase.price <= 0) { errors.push(`Phase ${index + 1}: Price must be positive`); } }); return errors; }

Support

For API support and questions: