{
  "openapi": "3.0.2",
  "info": {
    "title": "Shire Automations Planning API",
    "version": "1.1.0",
    "description": "OpenAPI documentation for the Shire Automations public planning API. It provides service and pricing information plus stateless business workflow planning calculations. Synchronous request bodies and results are not stored. With Prefer: respond-async, planning jobs temporarily store input and result for up to 15 minutes so clients can poll status. Async jobs retain one-way source-IP, Idempotency-Key, and input hashes until expiry. Each source IP can have 20 unexpired jobs, with 2,000 unexpired jobs across the service. Treat the statusUrl as a private bearer link: anyone with it can read the job result. Do not send credentials or sensitive customer, patient, or financial-account data. GET /api/v1/tools supports cursor pagination. All API responses include rate-limit headers; 429 responses include Retry-After. Errors use RFC 9457 Problem Details.",
    "contact": {
      "name": "Shire Automations",
      "url": "https://shireautomations.com/developers",
      "email": "contact@shireautomations.com"
    }
  },
  "servers": [{ "url": "https://shireautomations.com", "description": "Production" }],
  "externalDocs": {
    "description": "API versioning, pagination, retry, rate-limit, and deprecation policy",
    "url": "https://shireautomations.com/api-versioning"
  },
  "paths": {
    "/api/v1/catalog": {
      "get": {
        "operationId": "getCatalog",
        "summary": "Get services, starting prices, and planning tools",
        "responses": {
          "200": {
            "description": "Public Shire Automations catalog",
            "headers": {
              "X-API-Version": { "$ref": "#/components/headers/ApiVersion" },
              "RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" },
              "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" },
              "RateLimit-Reset": { "$ref": "#/components/headers/RateLimitReset" },
              "Deprecation": { "$ref": "#/components/headers/Deprecation" },
              "Sunset": { "$ref": "#/components/headers/Sunset" },
              "Link": { "$ref": "#/components/headers/DeprecationLink" }
            },
            "content": { "application/json": { "schema": { "type": "object", "additionalProperties": true } } }
          },
          "429": {
            "description": "Request limit reached. Retry after the indicated delay.",
            "headers": {
              "X-API-Version": { "$ref": "#/components/headers/ApiVersion" },
              "RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" },
              "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" },
              "RateLimit-Reset": { "$ref": "#/components/headers/RateLimitReset" },
              "Retry-After": { "$ref": "#/components/headers/RetryAfter" }
            },
            "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/Problem" } } }
          },
          "500": {
            "description": "Unexpected server error.",
            "headers": {
              "X-API-Version": { "$ref": "#/components/headers/ApiVersion" },
              "RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" },
              "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" },
              "RateLimit-Reset": { "$ref": "#/components/headers/RateLimitReset" }
            },
            "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/Problem" } } }
          }
        }
      }
    },
    "/api/v1/tools": {
      "get": {
        "operationId": "listPlanningTools",
        "summary": "List available planning tools",
        "description": "Lists planning calculators with cursor pagination. Set limit from 1 to 100. Send pagination.nextCursor as cursor in the next request; a null nextCursor ends pagination.",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum tools to return. Defaults to 20.",
            "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 20 }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Opaque cursor from pagination.nextCursor in the previous response.",
            "schema": { "type": "string", "maxLength": 128 }
          }
        ],
        "responses": {
          "200": {
            "description": "Planning tools and endpoint paths",
            "headers": {
              "X-API-Version": { "$ref": "#/components/headers/ApiVersion" },
              "RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" },
              "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" },
              "RateLimit-Reset": { "$ref": "#/components/headers/RateLimitReset" },
              "Deprecation": { "$ref": "#/components/headers/Deprecation" },
              "Sunset": { "$ref": "#/components/headers/Sunset" },
              "Link": { "$ref": "#/components/headers/DeprecationLink" }
            },
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PlanningToolList" } } }
          },
          "400": {
            "description": "Invalid pagination parameter.",
            "headers": {
              "X-API-Version": { "$ref": "#/components/headers/ApiVersion" },
              "RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" },
              "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" },
              "RateLimit-Reset": { "$ref": "#/components/headers/RateLimitReset" }
            },
            "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/Problem" } } }
          },
          "429": {
            "description": "Request limit reached. Retry after the indicated delay.",
            "headers": {
              "X-API-Version": { "$ref": "#/components/headers/ApiVersion" },
              "RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" },
              "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" },
              "RateLimit-Reset": { "$ref": "#/components/headers/RateLimitReset" },
              "Retry-After": { "$ref": "#/components/headers/RetryAfter" }
            },
            "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/Problem" } } }
          },
          "500": {
            "description": "Unexpected server error.",
            "headers": {
              "X-API-Version": { "$ref": "#/components/headers/ApiVersion" },
              "RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" },
              "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" },
              "RateLimit-Reset": { "$ref": "#/components/headers/RateLimitReset" }
            },
            "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/Problem" } } }
          }
        }
      }
    },
    "/api/v1/tools/{slug}": {
      "post": {
        "operationId": "calculatePlanningResult",
        "summary": "Calculate a workflow planning result",
        "description": "Runs one deterministic calculator synchronously by default. Send Prefer: respond-async and an Idempotency-Key to create a temporary job and receive 202 Accepted with its Location status URL. Async job inputs and results are available for up to 15 minutes, then deleted. At most 20 unexpired async jobs are retained per source IP, with 2,000 unexpired jobs across the service. Anyone with the returned statusUrl can read the job result. Synchronous requests and results are not stored. Keep sensitive customer and account data out of inputs.",
        "parameters": [{
          "name": "slug",
          "in": "path",
          "required": true,
          "schema": { "type": "string", "enum": ["automation-opportunity-scorecard", "workflow-mapper", "lead-response-calculator", "ai-readiness-assessment", "integration-finder", "client-onboarding-builder", "invoice-follow-up-calculator", "roi-calculator"] }
        }, {
          "name": "Idempotency-Key",
          "in": "header",
          "required": false,
          "description": "Optional for synchronous calls; required with Prefer: respond-async. Reusing the same key and input returns the existing job. Changing input requires a new key. Async jobs store only a hash of this key until expiry.",
          "schema": { "type": "string", "minLength": 1, "maxLength": 255, "pattern": "^[!-~]{1,255}$" }
        }, {
          "name": "Prefer",
          "in": "header",
          "required": false,
          "description": "Set to respond-async to create a pollable job instead of returning the calculation result synchronously.",
          "schema": { "type": "string", "enum": ["respond-async"] }
        }],
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PlanningRequest" } } }
        },
        "responses": {
          "200": {
            "description": "Calculated result",
            "headers": {
              "X-API-Version": { "$ref": "#/components/headers/ApiVersion" },
              "RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" },
              "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" },
              "RateLimit-Reset": { "$ref": "#/components/headers/RateLimitReset" },
              "Idempotency-Key": { "$ref": "#/components/headers/IdempotencyKey" },
              "Deprecation": { "$ref": "#/components/headers/Deprecation" },
              "Sunset": { "$ref": "#/components/headers/Sunset" },
              "Link": { "$ref": "#/components/headers/DeprecationLink" }
            },
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PlanningResponse" } } }
          },
          "202": {
            "description": "Planning job accepted. Poll the Location URL until status is completed or failed. The response includes jobId, status, statusUrl, createdAt, and expiresAt.",
            "headers": {
              "X-API-Version": { "$ref": "#/components/headers/ApiVersion" },
              "RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" },
              "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" },
              "RateLimit-Reset": { "$ref": "#/components/headers/RateLimitReset" },
              "Location": { "$ref": "#/components/headers/JobLocation" },
              "Retry-After": { "$ref": "#/components/headers/RetryAfter" },
              "Preference-Applied": { "$ref": "#/components/headers/PreferenceApplied" },
              "Idempotency-Key": { "$ref": "#/components/headers/IdempotencyKey" }
            },
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AsyncJob" } } }
          },
          "400": {
            "description": "Malformed JSON, invalid Idempotency-Key, or missing Idempotency-Key when requesting asynchronous processing.",
            "headers": {
              "X-API-Version": { "$ref": "#/components/headers/ApiVersion" },
              "RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" },
              "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" },
              "RateLimit-Reset": { "$ref": "#/components/headers/RateLimitReset" }
            },
            "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/Problem" } } }
          },
          "404": {
            "description": "Unknown planning tool.",
            "headers": {
              "X-API-Version": { "$ref": "#/components/headers/ApiVersion" },
              "RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" },
              "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" },
              "RateLimit-Reset": { "$ref": "#/components/headers/RateLimitReset" }
            },
            "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/Problem" } } }
          },
          "409": {
            "description": "The Idempotency-Key was already used with different input.",
            "headers": {
              "X-API-Version": { "$ref": "#/components/headers/ApiVersion" },
              "RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" },
              "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" },
              "RateLimit-Reset": { "$ref": "#/components/headers/RateLimitReset" }
            },
            "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/Problem" } } }
          },
          "413": {
            "description": "Request body exceeds 32,768 bytes.",
            "headers": {
              "X-API-Version": { "$ref": "#/components/headers/ApiVersion" },
              "RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" },
              "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" },
              "RateLimit-Reset": { "$ref": "#/components/headers/RateLimitReset" }
            },
            "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/Problem" } } }
          },
          "415": {
            "description": "Content-Type must be application/json.",
            "headers": {
              "X-API-Version": { "$ref": "#/components/headers/ApiVersion" },
              "RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" },
              "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" },
              "RateLimit-Reset": { "$ref": "#/components/headers/RateLimitReset" }
            },
            "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/Problem" } } }
          },
          "422": {
            "description": "Planning input is invalid or cannot be calculated.",
            "headers": {
              "X-API-Version": { "$ref": "#/components/headers/ApiVersion" },
              "RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" },
              "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" },
              "RateLimit-Reset": { "$ref": "#/components/headers/RateLimitReset" }
            },
            "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/Problem" } } }
          },
          "429": {
            "description": "Request or async-job capacity limit reached. There can be at most 20 unexpired jobs per source IP and 2,000 across the service. Retry after the indicated delay.",
            "headers": {
              "X-API-Version": { "$ref": "#/components/headers/ApiVersion" },
              "RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" },
              "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" },
              "RateLimit-Reset": { "$ref": "#/components/headers/RateLimitReset" },
              "Retry-After": { "$ref": "#/components/headers/RetryAfter" }
            },
            "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/Problem" } } }
          },
          "500": {
            "description": "Unexpected server error.",
            "headers": {
              "X-API-Version": { "$ref": "#/components/headers/ApiVersion" },
              "RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" },
              "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" },
              "RateLimit-Reset": { "$ref": "#/components/headers/RateLimitReset" }
            },
            "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/Problem" } } }
          }
        }
      }
    },
    "/api/v1/jobs/{jobId}": {
      "get": {
        "operationId": "getPlanningJob",
        "summary": "Get planning job status",
        "description": "Poll the statusUrl returned with 202 Accepted. Queued and running jobs return 200 with Retry-After: 1. Completed jobs include result. Failed jobs include a stable error code. Job data expires after 15 minutes. Anyone with the statusUrl can read its result; treat it as a private bearer link.",
        "parameters": [{
          "name": "jobId",
          "in": "path",
          "required": true,
          "schema": { "type": "string", "format": "uuid" }
        }],
        "responses": {
          "200": {
            "description": "Current job state; includes result when completed.",
            "headers": {
              "X-API-Version": { "$ref": "#/components/headers/ApiVersion" },
              "RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" },
              "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" },
              "RateLimit-Reset": { "$ref": "#/components/headers/RateLimitReset" },
              "Location": { "$ref": "#/components/headers/JobLocation" },
              "Retry-After": { "$ref": "#/components/headers/RetryAfter" }
            },
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AsyncJob" } } }
          },
          "404": {
            "description": "Job does not exist or has expired.",
            "headers": {
              "X-API-Version": { "$ref": "#/components/headers/ApiVersion" },
              "RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" },
              "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" },
              "RateLimit-Reset": { "$ref": "#/components/headers/RateLimitReset" }
            },
            "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/Problem" } } }
          },
          "429": {
            "description": "Request limit reached. Retry after the indicated delay.",
            "headers": {
              "X-API-Version": { "$ref": "#/components/headers/ApiVersion" },
              "RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" },
              "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" },
              "RateLimit-Reset": { "$ref": "#/components/headers/RateLimitReset" },
              "Retry-After": { "$ref": "#/components/headers/RetryAfter" }
            },
            "content": { "application/problem+json": { "schema": { "$ref": "#/components/schemas/Problem" } } }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Problem": {
        "type": "object",
        "required": ["type", "title", "status", "detail", "instance", "code"],
        "properties": {
          "type": { "type": "string", "format": "uri-reference", "example": "about:blank" },
          "title": { "type": "string", "description": "Short, stable summary of the problem." },
          "status": { "type": "integer", "description": "HTTP status code." },
          "detail": { "type": "string", "description": "Human-readable explanation specific to this response." },
          "instance": { "type": "string", "format": "uri-reference", "description": "Request path that produced the problem." },
          "code": { "type": "string", "description": "Stable machine-readable error code." }
        },
        "additionalProperties": true
      },
      "PlanningTool": {
        "type": "object",
        "required": ["id", "name", "description", "path", "endpoint", "method"],
        "properties": {
          "id": { "type": "string" },
          "name": { "type": "string" },
          "description": { "type": "string" },
          "path": { "type": "string" },
          "endpoint": { "type": "string", "format": "uri-reference" },
          "method": { "type": "string", "enum": ["POST"] }
        }
      },
      "PlanningToolList": {
        "type": "object",
        "required": ["version", "tools", "pagination", "openapi"],
        "properties": {
          "version": { "type": "string", "enum": ["1"] },
          "tools": { "type": "array", "items": { "$ref": "#/components/schemas/PlanningTool" } },
          "pagination": {
            "type": "object",
            "required": ["limit", "nextCursor", "hasMore"],
            "properties": {
              "limit": { "type": "integer", "minimum": 1, "maximum": 100 },
              "nextCursor": { "type": "string", "nullable": true, "description": "Opaque cursor for the next page, or null when complete." },
              "hasMore": { "type": "boolean" }
            }
          },
          "openapi": { "type": "string", "format": "uri" }
        }
      },
      "PlanningRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": ["input"],
        "properties": { "input": { "anyOf": [
          { "$ref": "#/components/schemas/AutomationOpportunityInput" },
          { "$ref": "#/components/schemas/WorkflowMapperInput" },
          { "$ref": "#/components/schemas/LeadResponseInput" },
          { "$ref": "#/components/schemas/AiReadinessInput" },
          { "$ref": "#/components/schemas/IntegrationFinderInput" },
          { "$ref": "#/components/schemas/ClientOnboardingInput" },
          { "$ref": "#/components/schemas/InvoiceFollowUpInput" },
          { "$ref": "#/components/schemas/RoiInput" }
        ] } }
      },
      "PlanningResponse": {
        "type": "object",
        "required": ["version", "tool", "result"],
        "properties": { "version": { "type": "string", "enum": ["1"] }, "tool": { "type": "string" }, "result": { "type": "object", "additionalProperties": true } }
      },
      "AsyncJob": {
        "type": "object",
        "required": ["jobId", "status", "statusUrl", "createdAt", "expiresAt"],
        "properties": {
          "jobId": { "type": "string", "format": "uuid" },
          "status": { "type": "string", "enum": ["queued", "running", "completed", "failed"] },
          "statusUrl": { "type": "string", "format": "uri-reference" },
          "createdAt": { "type": "string", "format": "date-time" },
          "expiresAt": { "type": "string", "format": "date-time" },
          "result": { "$ref": "#/components/schemas/PlanningResponse" },
          "error": {
            "type": "object",
            "required": ["code", "message"],
            "properties": { "code": { "type": "string" }, "message": { "type": "string" } }
          }
        }
      },
      "AutomationOpportunityInput": {
        "type": "object",
        "properties": { "processes": { "type": "array", "maxItems": 5, "items": { "type": "object", "properties": {
          "name": { "type": "string", "maxLength": 160 }, "occurrencesPerWeek": { "type": "number", "minimum": 0 }, "minutesPerOccurrence": { "type": "number", "minimum": 0, "maximum": 1440 }, "rules": { "type": "string", "enum": ["judgment", "mixed", "clear"] }, "stability": { "type": "string", "enum": ["changing", "mostly-stable", "stable"] }, "inputQuality": { "type": "string", "enum": ["scattered", "mixed", "structured"] }, "systemAccess": { "type": "string", "enum": ["manual", "export", "connected"] }, "failureImpact": { "type": "string", "enum": ["low", "medium", "high"] }, "reversibility": { "type": "string", "enum": ["easy", "partial", "hard"] }, "sensitiveData": { "type": "string", "enum": ["no", "yes"] }
        } } } }
      },
      "WorkflowMapperInput": {
        "type": "object",
        "properties": { "workflowName": { "type": "string" }, "trigger": { "type": "string" }, "outcome": { "type": "string" }, "steps": { "type": "array", "maxItems": 8, "items": { "type": "object", "properties": { "name": { "type": "string" }, "owner": { "type": "string" }, "tool": { "type": "string" }, "kind": { "type": "string", "enum": ["task", "decision", "handoff"] } } } } }
      },
      "LeadResponseInput": {
        "type": "object",
        "properties": { "monthlyLeads": { "type": "number", "minimum": 0 }, "lateResponseShare": { "type": "number", "minimum": 0, "maximum": 100 }, "currentResponseMinutes": { "type": "number", "minimum": 0 }, "targetResponseMinutes": { "type": "number", "minimum": 1 }, "currentConversionRate": { "type": "number", "minimum": 0, "maximum": 100 }, "conversionLiftPoints": { "type": "number", "minimum": 0 }, "grossProfitPerConversion": { "type": "number", "minimum": 0 }, "manualFollowUpMinutes": { "type": "number", "minimum": 0 }, "loadedHourlyCost": { "type": "number", "minimum": 0 } }
      },
      "AiReadinessInput": { "type": "object", "properties": { "goal": { "type": "integer", "minimum": 0, "maximum": 2 }, "process": { "type": "integer", "minimum": 0, "maximum": 2 }, "data": { "type": "integer", "minimum": 0, "maximum": 2 }, "systems": { "type": "integer", "minimum": 0, "maximum": 2 }, "ownership": { "type": "integer", "minimum": 0, "maximum": 2 }, "oversight": { "type": "integer", "minimum": 0, "maximum": 2 } } },
      "IntegrationFinderInput": {
        "type": "object",
        "properties": { "sourceApp": { "type": "string", "enum": ["google-forms", "google-sheets", "gmail", "google-calendar", "calendly", "quickbooks", "hubspot", "slack", "notion", "stripe", "airtable", "shopify"] }, "destinationApp": { "type": "string", "enum": ["google-forms", "google-sheets", "gmail", "google-calendar", "calendly", "quickbooks", "hubspot", "slack", "notion", "stripe", "airtable", "shopify"] }, "processType": { "type": "string", "enum": ["lead", "appointment", "invoice", "customer", "task", "report"] }, "volumePerMonth": { "type": "number", "minimum": 0 } }
      },
      "ClientOnboardingInput": {
        "type": "object",
        "properties": { "businessType": { "type": "string", "enum": ["professional", "home-services", "agency", "retail", "healthcare", "nonprofit", "other"] }, "serviceType": { "type": "string" }, "engagement": { "type": "string", "enum": ["one-off", "recurring"] }, "firstMilestoneDays": { "type": "integer", "minimum": 1, "maximum": 180 }, "companyName": { "type": "string" } }
      },
      "InvoiceFollowUpInput": {
        "type": "object",
        "properties": { "overdueInvoices": { "type": "number", "minimum": 0 }, "totalOutstanding": { "type": "number", "minimum": 0 }, "followUpsPerInvoice": { "type": "number", "minimum": 0 }, "minutesPerFollowUp": { "type": "number", "minimum": 0 }, "loadedHourlyCost": { "type": "number", "minimum": 0 }, "followUpCompletionRate": { "type": "number", "minimum": 0, "maximum": 100 }, "averageDaysOverdue": { "type": "number", "minimum": 0 } }
      },
      "RoiInput": {
        "type": "object",
        "description": "ROI calculator inputs. All values are estimates supplied by the caller; results are planning scenarios, not forecasts.",
        "properties": { "scenario": { "type": "string", "enum": ["conservative", "expected", "strong"] }, "inputs": { "type": "object", "additionalProperties": { "oneOf": [{ "type": "number" }, { "type": "string" }] } } }
      }
    },
    "headers": {
      "ApiVersion": {
        "description": "Major API version used by the response.",
        "schema": { "type": "string", "example": "1" }
      },
      "RateLimitLimit": {
        "description": "Requests allowed per fixed 60-second window for this source IP.",
        "schema": { "type": "integer", "example": 60 }
      },
      "RateLimitRemaining": {
        "description": "Requests remaining in the current window.",
        "schema": { "type": "integer", "example": 59 }
      },
      "RateLimitReset": {
        "description": "Seconds until the current rate-limit window resets.",
        "schema": { "type": "integer", "example": 60 }
      },
      "RetryAfter": {
        "description": "Seconds to wait before retrying a rate-limited request.",
        "schema": { "type": "integer", "minimum": 1 }
      },
      "JobLocation": {
        "description": "Status URL for a planning job.",
        "schema": { "type": "string", "format": "uri-reference" }
      },
      "PreferenceApplied": {
        "description": "Preference honored by the server.",
        "schema": { "type": "string", "enum": ["respond-async"] }
      },
      "IdempotencyKey": {
        "description": "Echo of the raw request key. Async mode stores only a one-way hash of the key until job expiry.",
        "schema": { "type": "string", "maxLength": 255 }
      },
      "Deprecation": {
        "description": "Present when a resource is deprecated; follows RFC 9745.",
        "schema": { "type": "string", "example": "@1798761600" }
      },
      "Sunset": {
        "description": "Present when a removal date is set; follows RFC 8594.",
        "schema": { "type": "string", "example": "Tue, 31 Dec 2027 23:59:59 GMT" }
      },
      "DeprecationLink": {
        "description": "Link to migration information when an endpoint is deprecated.",
        "schema": { "type": "string", "example": "<https://shireautomations.com/api-versioning>; rel=\"deprecation\"" }
      }
    }
  }
}
