{
  "openapi": "3.0.3",
  "info": {
    "title": "Project Cost Estimator API",
    "description": "Website and web-app cost estimates from the same nine engines as the calculator at projectcostestimator.com, calibrated against 600+ project quotes and public rate benchmarks across six markets. Free tier: 100 requests per month per key, key emailed on request, no signup. The cost dataset behind the engine is open (CC BY 4.0). Cite as \"Project Cost Estimator (projectcostestimator.com)\".",
    "version": "1.1.0",
    "contact": {
      "name": "Project Cost Estimator",
      "url": "https://projectcostestimator.com/contact",
      "email": "hello@projectcostestimator.com"
    },
    "license": {
      "name": "Data: CC BY 4.0",
      "url": "https://creativecommons.org/licenses/by/4.0/"
    }
  },
  "servers": [
    {
      "url": "https://projectcostestimator.com",
      "description": "Production"
    }
  ],
  "components": {
    "securitySchemes": {
      "bearerKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "Authorization: Bearer pce_... (scheme is case-insensitive). Get a key at /api-docs or POST /api/keys."
      },
      "apiKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "The same key in an X-API-Key header."
      }
    },
    "schemas": {
      "EstimateInput": {
        "type": "object",
        "additionalProperties": true,
        "description": "Any subset of the calculator's fields; unset fields use the calculator's defaults. Unknown keys are ignored and echoed back. Accepted aliases: platform -> forcePlatform, developerLocation -> market, location -> market, region -> market, country -> market, tier -> pricingTier, builder -> pricingTier, type -> projectType, project -> projectType, pages -> numberOfPages, products -> numberOfProducts, origin -> projectOrigin, client -> clientType, timeline -> urgency, design -> designType. Values are matched case-insensitively; booleans map to yes/no; a bare number for numberOfPages or numberOfProducts is banded.",
        "properties": {
          "pricingTier": {
            "type": "string",
            "enum": [
              "freelancer",
              "agency"
            ],
            "description": "Who builds it."
          },
          "market": {
            "type": "string",
            "enum": [
              "eastern_europe",
              "western_europe",
              "uk",
              "us",
              "australia",
              "south_asia"
            ],
            "description": "Where the developer is; sets the hourly rate band."
          },
          "projectType": {
            "type": "string",
            "enum": [
              "presentation",
              "portfolio",
              "blog",
              "landing",
              "ecommerce",
              "marketplace",
              "webapp"
            ],
            "description": "What is being built."
          },
          "projectOrigin": {
            "type": "string",
            "enum": [
              "new_build",
              "redesign",
              "migration"
            ]
          },
          "migrationFrom": {
            "type": "string",
            "maxLength": 64,
            "description": "Platform id when projectOrigin is migration."
          },
          "migrationTo": {
            "type": "string",
            "maxLength": 64
          },
          "numberOfPages": {
            "type": "string",
            "enum": [
              "1-5",
              "5-15",
              "15-50",
              "50+"
            ],
            "description": "A plain number is accepted and banded (e.g. 12 -> \"5-15\")."
          },
          "numberOfProducts": {
            "type": "string",
            "enum": [
              "0",
              "1-50",
              "50-200",
              "200-1000",
              "1000-5000",
              "5000-50000",
              "50000+"
            ],
            "description": "A plain number is accepted and banded (e.g. 12 -> \"5-15\")."
          },
          "contentReady": {
            "type": "string",
            "enum": [
              "yes",
              "partial",
              "no"
            ]
          },
          "clientType": {
            "type": "string",
            "enum": [
              "startup",
              "small_business",
              "mid_market",
              "enterprise"
            ]
          },
          "urgency": {
            "type": "string",
            "enum": [
              "relaxed",
              "normal",
              "tight",
              "rush"
            ]
          },
          "revisionRounds": {
            "type": "string",
            "enum": [
              "1",
              "2",
              "3",
              "unlimited"
            ]
          },
          "designType": {
            "type": "string",
            "enum": [
              "template",
              "premium",
              "custom"
            ]
          },
          "animations": {
            "type": "string",
            "enum": [
              "none",
              "basic",
              "advanced"
            ]
          },
          "branding": {
            "type": "string",
            "enum": [
              "provided",
              "needs_creation"
            ]
          },
          "authentication": {
            "type": "string",
            "enum": [
              "none",
              "basic",
              "advanced"
            ]
          },
          "blog": {
            "type": "string",
            "enum": [
              "yes",
              "no"
            ]
          },
          "search": {
            "type": "string",
            "enum": [
              "none",
              "basic",
              "advanced"
            ]
          },
          "multilingual": {
            "type": "string",
            "enum": [
              "yes",
              "no"
            ]
          },
          "multiCurrency": {
            "type": "string",
            "enum": [
              "yes",
              "no"
            ]
          },
          "bookingSystem": {
            "type": "string",
            "enum": [
              "yes",
              "no"
            ]
          },
          "multiVendor": {
            "type": "string",
            "enum": [
              "yes",
              "no"
            ]
          },
          "payments": {
            "type": "string",
            "enum": [
              "basic",
              "multiple"
            ]
          },
          "shipping": {
            "type": "string",
            "enum": [
              "basic",
              "advanced"
            ]
          },
          "invoicing": {
            "type": "string",
            "enum": [
              "yes",
              "no"
            ]
          },
          "promotions": {
            "type": "string",
            "enum": [
              "none",
              "basic",
              "advanced"
            ]
          },
          "crm": {
            "type": "string",
            "enum": [
              "none",
              "basic",
              "advanced"
            ]
          },
          "erp": {
            "type": "string",
            "enum": [
              "none",
              "yes"
            ]
          },
          "thirdPartyApis": {
            "type": "string",
            "enum": [
              "none",
              "few",
              "many"
            ]
          },
          "emailNewsletter": {
            "type": "string",
            "enum": [
              "none",
              "basic",
              "advanced"
            ]
          },
          "socialMedia": {
            "type": "string",
            "enum": [
              "none",
              "basic",
              "advanced"
            ]
          },
          "analytics": {
            "type": "string",
            "enum": [
              "none",
              "basic",
              "advanced"
            ]
          },
          "contactForms": {
            "type": "string",
            "enum": [
              "none",
              "basic",
              "advanced"
            ]
          },
          "liveChat": {
            "type": "string",
            "enum": [
              "none",
              "basic",
              "ai_chatbot"
            ]
          },
          "accessibility": {
            "type": "string",
            "enum": [
              "none",
              "basic",
              "aa_compliant"
            ]
          },
          "legalGdpr": {
            "type": "string",
            "enum": [
              "none",
              "basic",
              "full"
            ]
          },
          "performance": {
            "type": "string",
            "enum": [
              "none",
              "basic",
              "advanced"
            ]
          },
          "contentCreation": {
            "type": "object",
            "properties": {
              "copywriting": {
                "type": "string",
                "enum": [
                  "none",
                  "basic",
                  "professional"
                ]
              },
              "photography": {
                "type": "string",
                "enum": [
                  "none",
                  "stock",
                  "custom_shoot"
                ]
              },
              "video": {
                "type": "string",
                "enum": [
                  "none",
                  "stock_clips",
                  "custom_production"
                ]
              },
              "contentStrategy": {
                "type": "string",
                "enum": [
                  "none",
                  "basic",
                  "full"
                ]
              }
            },
            "additionalProperties": false
          },
          "training": {
            "type": "string",
            "enum": [
              "none",
              "basic_documentation",
              "video_walkthrough",
              "live_sessions"
            ]
          },
          "seo": {
            "type": "string",
            "enum": [
              "none",
              "basic",
              "advanced"
            ]
          },
          "adsSetup": {
            "type": "string",
            "enum": [
              "yes",
              "no"
            ]
          },
          "maintenancePlan": {
            "type": "string",
            "enum": [
              "none",
              "basic",
              "full"
            ]
          },
          "warrantyPeriod": {
            "type": "string",
            "enum": [
              "none",
              "30_days",
              "90_days",
              "6_months",
              "12_months"
            ]
          },
          "forcePlatform": {
            "type": "string",
            "enum": [
              "wordpress",
              "shopify",
              "shopify_plus",
              "woocommerce",
              "magento2",
              "magento1",
              "prestashop",
              "bigcommerce",
              "wix",
              "squarespace",
              "webflow",
              "custom"
            ],
            "nullable": true,
            "description": "Pin the platform; omit or null to let the engine recommend one."
          }
        }
      },
      "EstimateResponse": {
        "type": "object",
        "properties": {
          "totalCost": {
            "type": "number",
            "description": "Total one-time build cost in USD."
          },
          "currency": {
            "type": "string",
            "enum": [
              "USD"
            ]
          },
          "platform": {
            "type": "string",
            "description": "Platform id the engine chose or that forcePlatform pinned."
          },
          "platformLabel": {
            "type": "string"
          },
          "timelineWeeks": {
            "type": "number"
          },
          "monthlyCost": {
            "type": "number",
            "description": "Recurring monthly cost in USD (hosting, licences, maintenance)."
          },
          "complexity": {
            "type": "number"
          },
          "complexityLevel": {
            "type": "string"
          },
          "riskLevel": {
            "type": "string"
          },
          "riskScore": {
            "type": "number"
          },
          "confidence": {
            "type": "object"
          },
          "costBreakdown": {
            "type": "object",
            "properties": {
              "basePrice": {
                "type": "number"
              },
              "featureAdditions": {
                "type": "number"
              },
              "developmentCost": {
                "type": "number"
              },
              "contingency": {
                "type": "number"
              },
              "totalHours": {
                "type": "number"
              },
              "hourlyRate": {
                "type": "number"
              }
            }
          },
          "input": {
            "type": "object",
            "description": "What the engine used: `applied` (after aliases and banding), `ignored` (unknown keys), `defaultsFor` (fields left at their defaults).",
            "properties": {
              "applied": {
                "type": "object"
              },
              "ignored": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "defaultsFor": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          },
          "meta": {
            "type": "object",
            "properties": {
              "engine": {
                "type": "string"
              },
              "calibration": {
                "type": "string"
              },
              "docs": {
                "type": "string"
              }
            }
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string"
          },
          "docs": {
            "type": "string"
          },
          "invalid": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "field": {
                  "type": "string"
                },
                "given": {},
                "allowed": {}
              }
            },
            "description": "Present on 400: each field with a value outside its enum, and what is allowed."
          },
          "ignored": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "fields": {
            "type": "object",
            "description": "The full field reference (field -> allowed values)."
          }
        }
      }
    }
  },
  "paths": {
    "/api/v1/estimate": {
      "post": {
        "operationId": "estimateCost",
        "summary": "Estimate the cost of a website or web app",
        "description": "Returns total cost, timeline, monthly cost, complexity, risk, confidence and a cost breakdown for the given scope. Send any subset of the fields; the response says which were applied and which fell back to defaults. Limits: 10 requests then 1 every 2 seconds (429 with Retry-After), 100 per calendar month per key (X-RateLimit-Remaining). Body limit 32 KB.",
        "security": [
          {
            "bearerKey": []
          },
          {
            "apiKeyHeader": []
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EstimateInput"
              },
              "example": {
                "projectType": "ecommerce",
                "market": "us",
                "pricingTier": "agency",
                "numberOfProducts": 120,
                "multilingual": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The estimate.",
            "headers": {
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EstimateResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, or a field with a value outside its enum (see `invalid` and `fields`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "413": {
            "description": "Body over 32 KB."
          },
          "429": {
            "description": "Burst limit (Retry-After in seconds) or monthly quota reached.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      },
      "get": {
        "operationId": "estimateCostByQuery",
        "summary": "The same estimate from query parameters",
        "description": "Every field of EstimateInput as a query parameter (e.g. ?projectType=ecommerce&market=us&numberOfProducts=120); nested fields with a dot (contentCreation.video=stock_clips). The key travels in a header, never in the URL.",
        "security": [
          {
            "bearerKey": []
          },
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "pricingTier",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "freelancer",
                "agency"
              ]
            }
          },
          {
            "name": "market",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "eastern_europe",
                "western_europe",
                "uk",
                "us",
                "australia",
                "south_asia"
              ]
            }
          },
          {
            "name": "projectType",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "presentation",
                "portfolio",
                "blog",
                "landing",
                "ecommerce",
                "marketplace",
                "webapp"
              ]
            }
          },
          {
            "name": "projectOrigin",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "new_build",
                "redesign",
                "migration"
              ]
            }
          },
          {
            "name": "migrationFrom",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "migrationTo",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "numberOfPages",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "1-5",
                "5-15",
                "15-50",
                "50+"
              ]
            }
          },
          {
            "name": "numberOfProducts",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "0",
                "1-50",
                "50-200",
                "200-1000",
                "1000-5000",
                "5000-50000",
                "50000+"
              ]
            }
          },
          {
            "name": "contentReady",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "yes",
                "partial",
                "no"
              ]
            }
          },
          {
            "name": "clientType",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "startup",
                "small_business",
                "mid_market",
                "enterprise"
              ]
            }
          },
          {
            "name": "urgency",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "relaxed",
                "normal",
                "tight",
                "rush"
              ]
            }
          },
          {
            "name": "revisionRounds",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "1",
                "2",
                "3",
                "unlimited"
              ]
            }
          },
          {
            "name": "designType",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "template",
                "premium",
                "custom"
              ]
            }
          },
          {
            "name": "animations",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "none",
                "basic",
                "advanced"
              ]
            }
          },
          {
            "name": "branding",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "provided",
                "needs_creation"
              ]
            }
          },
          {
            "name": "authentication",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "none",
                "basic",
                "advanced"
              ]
            }
          },
          {
            "name": "blog",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "yes",
                "no"
              ]
            }
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "none",
                "basic",
                "advanced"
              ]
            }
          },
          {
            "name": "multilingual",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "yes",
                "no"
              ]
            }
          },
          {
            "name": "multiCurrency",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "yes",
                "no"
              ]
            }
          },
          {
            "name": "bookingSystem",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "yes",
                "no"
              ]
            }
          },
          {
            "name": "multiVendor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "yes",
                "no"
              ]
            }
          },
          {
            "name": "payments",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "basic",
                "multiple"
              ]
            }
          },
          {
            "name": "shipping",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "basic",
                "advanced"
              ]
            }
          },
          {
            "name": "invoicing",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "yes",
                "no"
              ]
            }
          },
          {
            "name": "promotions",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "none",
                "basic",
                "advanced"
              ]
            }
          },
          {
            "name": "crm",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "none",
                "basic",
                "advanced"
              ]
            }
          },
          {
            "name": "erp",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "none",
                "yes"
              ]
            }
          },
          {
            "name": "thirdPartyApis",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "none",
                "few",
                "many"
              ]
            }
          },
          {
            "name": "emailNewsletter",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "none",
                "basic",
                "advanced"
              ]
            }
          },
          {
            "name": "socialMedia",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "none",
                "basic",
                "advanced"
              ]
            }
          },
          {
            "name": "analytics",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "none",
                "basic",
                "advanced"
              ]
            }
          },
          {
            "name": "contactForms",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "none",
                "basic",
                "advanced"
              ]
            }
          },
          {
            "name": "liveChat",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "none",
                "basic",
                "ai_chatbot"
              ]
            }
          },
          {
            "name": "accessibility",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "none",
                "basic",
                "aa_compliant"
              ]
            }
          },
          {
            "name": "legalGdpr",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "none",
                "basic",
                "full"
              ]
            }
          },
          {
            "name": "performance",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "none",
                "basic",
                "advanced"
              ]
            }
          },
          {
            "name": "training",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "none",
                "basic_documentation",
                "video_walkthrough",
                "live_sessions"
              ]
            }
          },
          {
            "name": "seo",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "none",
                "basic",
                "advanced"
              ]
            }
          },
          {
            "name": "adsSetup",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "yes",
                "no"
              ]
            }
          },
          {
            "name": "maintenancePlan",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "none",
                "basic",
                "full"
              ]
            }
          },
          {
            "name": "warrantyPeriod",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "none",
                "30_days",
                "90_days",
                "6_months",
                "12_months"
              ]
            }
          },
          {
            "name": "forcePlatform",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "wordpress",
                "shopify",
                "shopify_plus",
                "woocommerce",
                "magento2",
                "magento1",
                "prestashop",
                "bigcommerce",
                "wix",
                "squarespace",
                "webflow",
                "custom"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The estimate.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EstimateResponse"
                }
              }
            }
          },
          "400": {
            "description": "A field with a value outside its enum."
          },
          "401": {
            "description": "Missing or invalid key."
          },
          "429": {
            "description": "Rate limited."
          }
        }
      }
    },
    "/api/keys": {
      "post": {
        "operationId": "requestApiKey",
        "summary": "Request a free API key (emailed)",
        "description": "Send {\"email\": \"you@company.com\"}; the key is emailed to that address and never returned in the response. 5 requests per minute per IP. Free tier: 100 estimates per month.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Accepted; the key is on its way by email.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid email."
          },
          "429": {
            "description": "Too many requests."
          },
          "502": {
            "description": "The email could not be sent; retry later."
          }
        }
      }
    },
    "/api/cost-data": {
      "get": {
        "operationId": "getCostData",
        "summary": "The open cost dataset behind the engine (CC BY 4.0)",
        "description": "Schema.org Dataset JSON: base values by project type, platform / market / tier / urgency / client-type / origin multipliers, medians by type and tier, platform subscription fees, methodology. No key, no rate limit.",
        "responses": {
          "200": {
            "description": "The dataset.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    }
  }
}
