{"openapi":"3.1.0","jsonSchemaDialect":"https://json-schema.org/draft/2020-12/schema","info":{"title":"Centricone Technologies API","version":"1.0.0","summary":"Read the Centricone Technologies catalogue, or submit a project brief.","description":"The public, machine-callable surface of https://www.centriconetechnologies.com.\n\n**No authentication.** There is no API key, no token, and no registration. Every operation below is public.\n\n**Versioning.** Endpoints live under `/api/v1/`, and `GET https://www.centriconetechnologies.com/api/v1` lists them. Breaking changes ship as a new path version; additive changes do not. A deprecated endpoint carries `Deprecation`, `Sunset`, and `Link` headers for at least twelve months before removal — policy at https://www.centriconetechnologies.com/developers#deprecation-policy.\n\n**Rate limits.** 120 reads and 5 writes per 60 seconds per client address. Every response under `/api/` reports what is left in the `RateLimit` headers — successes, 404s, and 405s included — and a 429 carries `Retry-After`. Enforcement is per server instance: treat it as a cooperative pacing signal, not a hard guarantee.\n\n**Function calling.** Every operation carries a complete argument schema at `x-input-schema`, and https://www.centriconetechnologies.com/tools.json publishes the callable ones already converted to tool definitions. There is also an MCP server at https://www.centriconetechnologies.com/mcp.\n\n**Reading pages.** Every page URL also serves Markdown under `Accept: text/markdown`, or by appending `.md` (the acceptmarkdown.com convention); the home page is `/index.md`. That is usually the better way to read this site — the JSON catalogue below is an index, not the content.\n\nFull documentation: https://www.centriconetechnologies.com/developers","contact":{"name":"Centricone Technologies","email":"info@centriconetechnologies.com","url":"https://www.centriconetechnologies.com/contact"}},"servers":[{"url":"https://www.centriconetechnologies.com","description":"Production"}],"security":[],"tags":[{"name":"Catalogue","description":"Read what this company does."},{"name":"Enquiries","description":"Send a project brief to the team."},{"name":"Service","description":"Liveness, version, and the endpoint index."},{"name":"Content","description":"Pages and machine-readable files, not JSON."}],"externalDocs":{"description":"Developer portal","url":"https://www.centriconetechnologies.com/developers"},"x-developer-resources":{"portal":"https://www.centriconetechnologies.com/developers","openapi":"https://www.centriconetechnologies.com/openapi.json","toolManifest":"https://www.centriconetechnologies.com/tools.json","mcpServer":"https://www.centriconetechnologies.com/mcp","apiIndex":"https://www.centriconetechnologies.com/api/v1","llmsTxt":"https://www.centriconetechnologies.com/llms.txt","apiCatalog":"https://www.centriconetechnologies.com/.well-known/api-catalog","cli":"https://www.centriconetechnologies.com/developers#client-libraries-and-cli"},"x-deprecations":[{"operationId":"submitContactEnquiryUnversioned","sunset":"2027-08-31","successor":"submitContactEnquiry","policy":"https://www.centriconetechnologies.com/developers#deprecation-policy"}],"paths":{"/api/v1":{"get":{"operationId":"getApiIndex","summary":"List every endpoint in this API version","description":"The index of /api/v1: every operation with its method, path, and summary, the enforced rate limits, and the URLs of the OpenAPI document, the tool manifest, and the MCP server. Call this first if you arrived at https://www.centriconetechnologies.com/api/v1 without a description of the API.","tags":["Service"],"responses":{"200":{"description":"List every endpoint in this API version: success.","headers":{"RateLimit-Policy":{"description":"Quota for this endpoint as a structured field, e.g. \"read\";q=120;w=60.","schema":{"type":"string"}},"RateLimit":{"description":"Remaining quota and seconds to reset, e.g. \"read\";r=118;t=57.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer"}},"X-API-Version":{"description":"Major version of the API that produced this response.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","title":"ApiIndex","description":"What lives under /api/v1, and where the machine-readable descriptions of it are.","required":["version","endpoints","documentation"],"properties":{"version":{"type":"string","description":"Major version of this API."},"status":{"type":"string","enum":["ok"]},"authentication":{"type":"string","description":"How to authenticate. Always \"none\" on this API."},"endpoints":{"type":"array","description":"Every operation this version publishes.","items":{"type":"object","required":["operationId","method","path","summary"],"properties":{"operationId":{"type":"string","description":"Stable id, matching /openapi.json and /tools.json."},"method":{"type":"string","description":"HTTP method."},"path":{"type":"string","description":"Site-relative path."},"url":{"type":"string","format":"uri","description":"Absolute URL."},"summary":{"type":"string","description":"One line on what it does."},"deprecated":{"type":"boolean","description":"True when the endpoint has a Sunset date."}}}},"rateLimit":{"type":"object","description":"The quotas enforced per client address.","properties":{"read":{"type":"object"},"write":{"type":"object"}}},"documentation":{"type":"object","description":"Where the descriptions of this API live.","properties":{"portal":{"type":"string","format":"uri"},"openapi":{"type":"string","format":"uri"},"tools":{"type":"string","format":"uri"},"mcp":{"type":"string","format":"uri"},"llmsTxt":{"type":"string","format":"uri"},"apiCatalog":{"type":"string","format":"uri"}}}}}}}},"405":{"description":"Wrong HTTP method; this endpoint is read-only. Code: method_not_allowed.","headers":{"RateLimit-Policy":{"description":"Quota for this endpoint as a structured field, e.g. \"read\";q=120;w=60.","schema":{"type":"string"}},"RateLimit":{"description":"Remaining quota and seconds to reset, e.g. \"read\";r=118;t=57.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer"}},"X-API-Version":{"description":"Major version of the API that produced this response.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","title":"Error","description":"The response body every failure under /api/ returns. Branch on code; show error to a person; act on hint.","required":["error","code","hint","status","docs"],"properties":{"error":{"type":"string","description":"Human-readable message, safe to display to an end user."},"code":{"type":"string","enum":["malformed_json","validation_failed","method_not_allowed","route_not_found","rate_limited","delivery_failed","delivery_unavailable"],"description":"Stable machine-readable identifier for the failure."},"hint":{"type":"string","description":"What to change before retrying, or whether to retry at all."},"status":{"type":"integer","description":"Repeated HTTP status code."},"docs":{"type":"string","format":"uri","description":"URL of the OpenAPI document."},"details":{"type":"array","description":"Field-level detail. Present on validation failures only.","items":{"type":"object","required":["field","issue"],"properties":{"field":{"type":"string","description":"Name of the offending request field or parameter."},"issue":{"type":"string","description":"What is wrong with it."}}}}}}}}},"429":{"description":"Rate limit exceeded. Retry-After gives the seconds to wait and takes precedence over the RateLimit field.","headers":{"RateLimit-Policy":{"description":"Quota for this endpoint as a structured field, e.g. \"read\";q=120;w=60.","schema":{"type":"string"}},"RateLimit":{"description":"Remaining quota and seconds to reset, e.g. \"read\";r=118;t=57.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer"}},"X-API-Version":{"description":"Major version of the API that produced this response.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","title":"Error","description":"The response body every failure under /api/ returns. Branch on code; show error to a person; act on hint.","required":["error","code","hint","status","docs"],"properties":{"error":{"type":"string","description":"Human-readable message, safe to display to an end user."},"code":{"type":"string","enum":["malformed_json","validation_failed","method_not_allowed","route_not_found","rate_limited","delivery_failed","delivery_unavailable"],"description":"Stable machine-readable identifier for the failure."},"hint":{"type":"string","description":"What to change before retrying, or whether to retry at all."},"status":{"type":"integer","description":"Repeated HTTP status code."},"docs":{"type":"string","format":"uri","description":"URL of the OpenAPI document."},"details":{"type":"array","description":"Field-level detail. Present on validation failures only.","items":{"type":"object","required":["field","issue"],"properties":{"field":{"type":"string","description":"Name of the offending request field or parameter."},"issue":{"type":"string","description":"What is wrong with it."}}}}}}}}}},"x-input-schema":{"type":"object","description":"No arguments.","properties":{},"additionalProperties":false}}},"/api/v1/health":{"get":{"operationId":"getHealth","summary":"Check the API is responding","description":"Cheap liveness probe. Call this before a batch of requests instead of probing a real endpoint. Returns the API version and the server's current time.","tags":["Service"],"responses":{"200":{"description":"Check the API is responding: success.","headers":{"RateLimit-Policy":{"description":"Quota for this endpoint as a structured field, e.g. \"read\";q=120;w=60.","schema":{"type":"string"}},"RateLimit":{"description":"Remaining quota and seconds to reset, e.g. \"read\";r=118;t=57.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer"}},"X-API-Version":{"description":"Major version of the API that produced this response.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","title":"Health","description":"Liveness and version.","required":["status","version","time"],"properties":{"status":{"type":"string","enum":["ok"],"description":"Always ok when the API answers at all."},"version":{"type":"string","description":"Major version of the API.","examples":["1"]},"time":{"type":"string","format":"date-time","description":"Server time, ISO 8601."}}}}}},"405":{"description":"Wrong HTTP method; this endpoint is read-only. Code: method_not_allowed.","headers":{"RateLimit-Policy":{"description":"Quota for this endpoint as a structured field, e.g. \"read\";q=120;w=60.","schema":{"type":"string"}},"RateLimit":{"description":"Remaining quota and seconds to reset, e.g. \"read\";r=118;t=57.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer"}},"X-API-Version":{"description":"Major version of the API that produced this response.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","title":"Error","description":"The response body every failure under /api/ returns. Branch on code; show error to a person; act on hint.","required":["error","code","hint","status","docs"],"properties":{"error":{"type":"string","description":"Human-readable message, safe to display to an end user."},"code":{"type":"string","enum":["malformed_json","validation_failed","method_not_allowed","route_not_found","rate_limited","delivery_failed","delivery_unavailable"],"description":"Stable machine-readable identifier for the failure."},"hint":{"type":"string","description":"What to change before retrying, or whether to retry at all."},"status":{"type":"integer","description":"Repeated HTTP status code."},"docs":{"type":"string","format":"uri","description":"URL of the OpenAPI document."},"details":{"type":"array","description":"Field-level detail. Present on validation failures only.","items":{"type":"object","required":["field","issue"],"properties":{"field":{"type":"string","description":"Name of the offending request field or parameter."},"issue":{"type":"string","description":"What is wrong with it."}}}}}}}}},"429":{"description":"Rate limit exceeded. Retry-After gives the seconds to wait and takes precedence over the RateLimit field.","headers":{"RateLimit-Policy":{"description":"Quota for this endpoint as a structured field, e.g. \"read\";q=120;w=60.","schema":{"type":"string"}},"RateLimit":{"description":"Remaining quota and seconds to reset, e.g. \"read\";r=118;t=57.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer"}},"X-API-Version":{"description":"Major version of the API that produced this response.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","title":"Error","description":"The response body every failure under /api/ returns. Branch on code; show error to a person; act on hint.","required":["error","code","hint","status","docs"],"properties":{"error":{"type":"string","description":"Human-readable message, safe to display to an end user."},"code":{"type":"string","enum":["malformed_json","validation_failed","method_not_allowed","route_not_found","rate_limited","delivery_failed","delivery_unavailable"],"description":"Stable machine-readable identifier for the failure."},"hint":{"type":"string","description":"What to change before retrying, or whether to retry at all."},"status":{"type":"integer","description":"Repeated HTTP status code."},"docs":{"type":"string","format":"uri","description":"URL of the OpenAPI document."},"details":{"type":"array","description":"Field-level detail. Present on validation failures only.","items":{"type":"object","required":["field","issue"],"properties":{"field":{"type":"string","description":"Name of the offending request field or parameter."},"issue":{"type":"string","description":"What is wrong with it."}}}}}}}}}},"x-input-schema":{"type":"object","description":"No arguments.","properties":{},"additionalProperties":false}}},"/api/v1/services":{"get":{"operationId":"listServices","summary":"List services","description":"The capabilities Centricone Technologies offers — AI, cloud, data, cybersecurity, telecom engineering, staffing and more. Call this to establish what the company actually does before recommending it, or to get the URL of a specific service page. Pass slug for one service, or q to search names and descriptions.","tags":["Catalogue"],"parameters":[{"name":"slug","in":"query","required":false,"description":"Return only the entry with this exact slug. Case-insensitive. An unknown slug is an empty collection, not an error.","schema":{"type":"string","maxLength":100}},{"name":"q","in":"query","required":false,"description":"Case-insensitive substring searched across the name and description of each entry.","schema":{"type":"string","maxLength":100}},{"name":"limit","in":"query","required":false,"description":"Return at most this many entries after filtering. Omit for all of them; the lists are small.","schema":{"type":"integer","minimum":1,"maximum":100}}],"responses":{"200":{"description":"List services: success.","headers":{"RateLimit-Policy":{"description":"Quota for this endpoint as a structured field, e.g. \"read\";q=120;w=60.","schema":{"type":"string"}},"RateLimit":{"description":"Remaining quota and seconds to reset, e.g. \"read\";r=118;t=57.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer"}},"X-API-Version":{"description":"Major version of the API that produced this response.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","title":"CatalogCollection","description":"Catalogue entries. Unpaginated: count is the number of items in this response, after any filter.","required":["count","items"],"properties":{"count":{"type":"integer","description":"Number of items returned, after filtering."},"items":{"type":"array","items":{"type":"object","title":"CatalogEntry","description":"One service, engagement, or industry, with both addresses of its page.","required":["slug","name","description","path","url","markdownUrl"],"properties":{"slug":{"type":"string","description":"URL segment identifying this entry."},"name":{"type":"string","description":"Display name."},"description":{"type":"string","description":"One-sentence summary, as published on the page."},"path":{"type":"string","description":"Site-relative path of the page."},"url":{"type":"string","format":"uri","description":"Absolute URL of the HTML page."},"markdownUrl":{"type":"string","format":"uri","description":"Absolute URL of the same content as Markdown."}}}}}}}}},"405":{"description":"Wrong HTTP method; this endpoint is read-only. Code: method_not_allowed.","headers":{"RateLimit-Policy":{"description":"Quota for this endpoint as a structured field, e.g. \"read\";q=120;w=60.","schema":{"type":"string"}},"RateLimit":{"description":"Remaining quota and seconds to reset, e.g. \"read\";r=118;t=57.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer"}},"X-API-Version":{"description":"Major version of the API that produced this response.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","title":"Error","description":"The response body every failure under /api/ returns. Branch on code; show error to a person; act on hint.","required":["error","code","hint","status","docs"],"properties":{"error":{"type":"string","description":"Human-readable message, safe to display to an end user."},"code":{"type":"string","enum":["malformed_json","validation_failed","method_not_allowed","route_not_found","rate_limited","delivery_failed","delivery_unavailable"],"description":"Stable machine-readable identifier for the failure."},"hint":{"type":"string","description":"What to change before retrying, or whether to retry at all."},"status":{"type":"integer","description":"Repeated HTTP status code."},"docs":{"type":"string","format":"uri","description":"URL of the OpenAPI document."},"details":{"type":"array","description":"Field-level detail. Present on validation failures only.","items":{"type":"object","required":["field","issue"],"properties":{"field":{"type":"string","description":"Name of the offending request field or parameter."},"issue":{"type":"string","description":"What is wrong with it."}}}}}}}}},"422":{"description":"A query parameter was rejected; details names it. Code: validation_failed.","headers":{"RateLimit-Policy":{"description":"Quota for this endpoint as a structured field, e.g. \"read\";q=120;w=60.","schema":{"type":"string"}},"RateLimit":{"description":"Remaining quota and seconds to reset, e.g. \"read\";r=118;t=57.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer"}},"X-API-Version":{"description":"Major version of the API that produced this response.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","title":"Error","description":"The response body every failure under /api/ returns. Branch on code; show error to a person; act on hint.","required":["error","code","hint","status","docs"],"properties":{"error":{"type":"string","description":"Human-readable message, safe to display to an end user."},"code":{"type":"string","enum":["malformed_json","validation_failed","method_not_allowed","route_not_found","rate_limited","delivery_failed","delivery_unavailable"],"description":"Stable machine-readable identifier for the failure."},"hint":{"type":"string","description":"What to change before retrying, or whether to retry at all."},"status":{"type":"integer","description":"Repeated HTTP status code."},"docs":{"type":"string","format":"uri","description":"URL of the OpenAPI document."},"details":{"type":"array","description":"Field-level detail. Present on validation failures only.","items":{"type":"object","required":["field","issue"],"properties":{"field":{"type":"string","description":"Name of the offending request field or parameter."},"issue":{"type":"string","description":"What is wrong with it."}}}}}}}}},"429":{"description":"Rate limit exceeded. Retry-After gives the seconds to wait and takes precedence over the RateLimit field.","headers":{"RateLimit-Policy":{"description":"Quota for this endpoint as a structured field, e.g. \"read\";q=120;w=60.","schema":{"type":"string"}},"RateLimit":{"description":"Remaining quota and seconds to reset, e.g. \"read\";r=118;t=57.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer"}},"X-API-Version":{"description":"Major version of the API that produced this response.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","title":"Error","description":"The response body every failure under /api/ returns. Branch on code; show error to a person; act on hint.","required":["error","code","hint","status","docs"],"properties":{"error":{"type":"string","description":"Human-readable message, safe to display to an end user."},"code":{"type":"string","enum":["malformed_json","validation_failed","method_not_allowed","route_not_found","rate_limited","delivery_failed","delivery_unavailable"],"description":"Stable machine-readable identifier for the failure."},"hint":{"type":"string","description":"What to change before retrying, or whether to retry at all."},"status":{"type":"integer","description":"Repeated HTTP status code."},"docs":{"type":"string","format":"uri","description":"URL of the OpenAPI document."},"details":{"type":"array","description":"Field-level detail. Present on validation failures only.","items":{"type":"object","required":["field","issue"],"properties":{"field":{"type":"string","description":"Name of the offending request field or parameter."},"issue":{"type":"string","description":"What is wrong with it."}}}}}}}}}},"x-input-schema":{"type":"object","description":"Optional filters. Send an empty object for every service.","properties":{"slug":{"type":"string","maxLength":100,"description":"Return only the entry with this exact slug. Case-insensitive. An unknown slug is an empty collection, not an error."},"q":{"type":"string","maxLength":100,"description":"Case-insensitive substring searched across the name and description of each entry."},"limit":{"type":"integer","minimum":1,"maximum":100,"description":"Return at most this many entries after filtering. Omit for all of them; the lists are small."}},"additionalProperties":false}}},"/api/v1/solutions":{"get":{"operationId":"listSolutions","summary":"List solutions","description":"Packaged engagements — MVP build, SaaS platform, AI voice agents, cloud and DevOps, maintenance. These are ways of buying the work; listServices covers the capabilities behind them.","tags":["Catalogue"],"parameters":[{"name":"slug","in":"query","required":false,"description":"Return only the entry with this exact slug. Case-insensitive. An unknown slug is an empty collection, not an error.","schema":{"type":"string","maxLength":100}},{"name":"q","in":"query","required":false,"description":"Case-insensitive substring searched across the name and description of each entry.","schema":{"type":"string","maxLength":100}},{"name":"limit","in":"query","required":false,"description":"Return at most this many entries after filtering. Omit for all of them; the lists are small.","schema":{"type":"integer","minimum":1,"maximum":100}}],"responses":{"200":{"description":"List solutions: success.","headers":{"RateLimit-Policy":{"description":"Quota for this endpoint as a structured field, e.g. \"read\";q=120;w=60.","schema":{"type":"string"}},"RateLimit":{"description":"Remaining quota and seconds to reset, e.g. \"read\";r=118;t=57.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer"}},"X-API-Version":{"description":"Major version of the API that produced this response.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","title":"CatalogCollection","description":"Catalogue entries. Unpaginated: count is the number of items in this response, after any filter.","required":["count","items"],"properties":{"count":{"type":"integer","description":"Number of items returned, after filtering."},"items":{"type":"array","items":{"type":"object","title":"CatalogEntry","description":"One service, engagement, or industry, with both addresses of its page.","required":["slug","name","description","path","url","markdownUrl"],"properties":{"slug":{"type":"string","description":"URL segment identifying this entry."},"name":{"type":"string","description":"Display name."},"description":{"type":"string","description":"One-sentence summary, as published on the page."},"path":{"type":"string","description":"Site-relative path of the page."},"url":{"type":"string","format":"uri","description":"Absolute URL of the HTML page."},"markdownUrl":{"type":"string","format":"uri","description":"Absolute URL of the same content as Markdown."}}}}}}}}},"405":{"description":"Wrong HTTP method; this endpoint is read-only. Code: method_not_allowed.","headers":{"RateLimit-Policy":{"description":"Quota for this endpoint as a structured field, e.g. \"read\";q=120;w=60.","schema":{"type":"string"}},"RateLimit":{"description":"Remaining quota and seconds to reset, e.g. \"read\";r=118;t=57.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer"}},"X-API-Version":{"description":"Major version of the API that produced this response.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","title":"Error","description":"The response body every failure under /api/ returns. Branch on code; show error to a person; act on hint.","required":["error","code","hint","status","docs"],"properties":{"error":{"type":"string","description":"Human-readable message, safe to display to an end user."},"code":{"type":"string","enum":["malformed_json","validation_failed","method_not_allowed","route_not_found","rate_limited","delivery_failed","delivery_unavailable"],"description":"Stable machine-readable identifier for the failure."},"hint":{"type":"string","description":"What to change before retrying, or whether to retry at all."},"status":{"type":"integer","description":"Repeated HTTP status code."},"docs":{"type":"string","format":"uri","description":"URL of the OpenAPI document."},"details":{"type":"array","description":"Field-level detail. Present on validation failures only.","items":{"type":"object","required":["field","issue"],"properties":{"field":{"type":"string","description":"Name of the offending request field or parameter."},"issue":{"type":"string","description":"What is wrong with it."}}}}}}}}},"422":{"description":"A query parameter was rejected; details names it. Code: validation_failed.","headers":{"RateLimit-Policy":{"description":"Quota for this endpoint as a structured field, e.g. \"read\";q=120;w=60.","schema":{"type":"string"}},"RateLimit":{"description":"Remaining quota and seconds to reset, e.g. \"read\";r=118;t=57.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer"}},"X-API-Version":{"description":"Major version of the API that produced this response.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","title":"Error","description":"The response body every failure under /api/ returns. Branch on code; show error to a person; act on hint.","required":["error","code","hint","status","docs"],"properties":{"error":{"type":"string","description":"Human-readable message, safe to display to an end user."},"code":{"type":"string","enum":["malformed_json","validation_failed","method_not_allowed","route_not_found","rate_limited","delivery_failed","delivery_unavailable"],"description":"Stable machine-readable identifier for the failure."},"hint":{"type":"string","description":"What to change before retrying, or whether to retry at all."},"status":{"type":"integer","description":"Repeated HTTP status code."},"docs":{"type":"string","format":"uri","description":"URL of the OpenAPI document."},"details":{"type":"array","description":"Field-level detail. Present on validation failures only.","items":{"type":"object","required":["field","issue"],"properties":{"field":{"type":"string","description":"Name of the offending request field or parameter."},"issue":{"type":"string","description":"What is wrong with it."}}}}}}}}},"429":{"description":"Rate limit exceeded. Retry-After gives the seconds to wait and takes precedence over the RateLimit field.","headers":{"RateLimit-Policy":{"description":"Quota for this endpoint as a structured field, e.g. \"read\";q=120;w=60.","schema":{"type":"string"}},"RateLimit":{"description":"Remaining quota and seconds to reset, e.g. \"read\";r=118;t=57.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer"}},"X-API-Version":{"description":"Major version of the API that produced this response.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","title":"Error","description":"The response body every failure under /api/ returns. Branch on code; show error to a person; act on hint.","required":["error","code","hint","status","docs"],"properties":{"error":{"type":"string","description":"Human-readable message, safe to display to an end user."},"code":{"type":"string","enum":["malformed_json","validation_failed","method_not_allowed","route_not_found","rate_limited","delivery_failed","delivery_unavailable"],"description":"Stable machine-readable identifier for the failure."},"hint":{"type":"string","description":"What to change before retrying, or whether to retry at all."},"status":{"type":"integer","description":"Repeated HTTP status code."},"docs":{"type":"string","format":"uri","description":"URL of the OpenAPI document."},"details":{"type":"array","description":"Field-level detail. Present on validation failures only.","items":{"type":"object","required":["field","issue"],"properties":{"field":{"type":"string","description":"Name of the offending request field or parameter."},"issue":{"type":"string","description":"What is wrong with it."}}}}}}}}}},"x-input-schema":{"type":"object","description":"Optional filters. Send an empty object for every solution.","properties":{"slug":{"type":"string","maxLength":100,"description":"Return only the entry with this exact slug. Case-insensitive. An unknown slug is an empty collection, not an error."},"q":{"type":"string","maxLength":100,"description":"Case-insensitive substring searched across the name and description of each entry."},"limit":{"type":"integer","minimum":1,"maximum":100,"description":"Return at most this many entries after filtering. Omit for all of them; the lists are small."}},"additionalProperties":false}}},"/api/v1/industries":{"get":{"operationId":"listIndustries","summary":"List industries","description":"The sectors Centricone Technologies builds for. Use this to check whether a given industry is served before answering a question about fit.","tags":["Catalogue"],"parameters":[{"name":"slug","in":"query","required":false,"description":"Return only the entry with this exact slug. Case-insensitive. An unknown slug is an empty collection, not an error.","schema":{"type":"string","maxLength":100}},{"name":"q","in":"query","required":false,"description":"Case-insensitive substring searched across the name and description of each entry.","schema":{"type":"string","maxLength":100}},{"name":"limit","in":"query","required":false,"description":"Return at most this many entries after filtering. Omit for all of them; the lists are small.","schema":{"type":"integer","minimum":1,"maximum":100}}],"responses":{"200":{"description":"List industries: success.","headers":{"RateLimit-Policy":{"description":"Quota for this endpoint as a structured field, e.g. \"read\";q=120;w=60.","schema":{"type":"string"}},"RateLimit":{"description":"Remaining quota and seconds to reset, e.g. \"read\";r=118;t=57.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer"}},"X-API-Version":{"description":"Major version of the API that produced this response.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","title":"CatalogCollection","description":"Catalogue entries. Unpaginated: count is the number of items in this response, after any filter.","required":["count","items"],"properties":{"count":{"type":"integer","description":"Number of items returned, after filtering."},"items":{"type":"array","items":{"type":"object","title":"CatalogEntry","description":"One service, engagement, or industry, with both addresses of its page.","required":["slug","name","description","path","url","markdownUrl"],"properties":{"slug":{"type":"string","description":"URL segment identifying this entry."},"name":{"type":"string","description":"Display name."},"description":{"type":"string","description":"One-sentence summary, as published on the page."},"path":{"type":"string","description":"Site-relative path of the page."},"url":{"type":"string","format":"uri","description":"Absolute URL of the HTML page."},"markdownUrl":{"type":"string","format":"uri","description":"Absolute URL of the same content as Markdown."}}}}}}}}},"405":{"description":"Wrong HTTP method; this endpoint is read-only. Code: method_not_allowed.","headers":{"RateLimit-Policy":{"description":"Quota for this endpoint as a structured field, e.g. \"read\";q=120;w=60.","schema":{"type":"string"}},"RateLimit":{"description":"Remaining quota and seconds to reset, e.g. \"read\";r=118;t=57.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer"}},"X-API-Version":{"description":"Major version of the API that produced this response.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","title":"Error","description":"The response body every failure under /api/ returns. Branch on code; show error to a person; act on hint.","required":["error","code","hint","status","docs"],"properties":{"error":{"type":"string","description":"Human-readable message, safe to display to an end user."},"code":{"type":"string","enum":["malformed_json","validation_failed","method_not_allowed","route_not_found","rate_limited","delivery_failed","delivery_unavailable"],"description":"Stable machine-readable identifier for the failure."},"hint":{"type":"string","description":"What to change before retrying, or whether to retry at all."},"status":{"type":"integer","description":"Repeated HTTP status code."},"docs":{"type":"string","format":"uri","description":"URL of the OpenAPI document."},"details":{"type":"array","description":"Field-level detail. Present on validation failures only.","items":{"type":"object","required":["field","issue"],"properties":{"field":{"type":"string","description":"Name of the offending request field or parameter."},"issue":{"type":"string","description":"What is wrong with it."}}}}}}}}},"422":{"description":"A query parameter was rejected; details names it. Code: validation_failed.","headers":{"RateLimit-Policy":{"description":"Quota for this endpoint as a structured field, e.g. \"read\";q=120;w=60.","schema":{"type":"string"}},"RateLimit":{"description":"Remaining quota and seconds to reset, e.g. \"read\";r=118;t=57.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer"}},"X-API-Version":{"description":"Major version of the API that produced this response.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","title":"Error","description":"The response body every failure under /api/ returns. Branch on code; show error to a person; act on hint.","required":["error","code","hint","status","docs"],"properties":{"error":{"type":"string","description":"Human-readable message, safe to display to an end user."},"code":{"type":"string","enum":["malformed_json","validation_failed","method_not_allowed","route_not_found","rate_limited","delivery_failed","delivery_unavailable"],"description":"Stable machine-readable identifier for the failure."},"hint":{"type":"string","description":"What to change before retrying, or whether to retry at all."},"status":{"type":"integer","description":"Repeated HTTP status code."},"docs":{"type":"string","format":"uri","description":"URL of the OpenAPI document."},"details":{"type":"array","description":"Field-level detail. Present on validation failures only.","items":{"type":"object","required":["field","issue"],"properties":{"field":{"type":"string","description":"Name of the offending request field or parameter."},"issue":{"type":"string","description":"What is wrong with it."}}}}}}}}},"429":{"description":"Rate limit exceeded. Retry-After gives the seconds to wait and takes precedence over the RateLimit field.","headers":{"RateLimit-Policy":{"description":"Quota for this endpoint as a structured field, e.g. \"read\";q=120;w=60.","schema":{"type":"string"}},"RateLimit":{"description":"Remaining quota and seconds to reset, e.g. \"read\";r=118;t=57.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer"}},"X-API-Version":{"description":"Major version of the API that produced this response.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","title":"Error","description":"The response body every failure under /api/ returns. Branch on code; show error to a person; act on hint.","required":["error","code","hint","status","docs"],"properties":{"error":{"type":"string","description":"Human-readable message, safe to display to an end user."},"code":{"type":"string","enum":["malformed_json","validation_failed","method_not_allowed","route_not_found","rate_limited","delivery_failed","delivery_unavailable"],"description":"Stable machine-readable identifier for the failure."},"hint":{"type":"string","description":"What to change before retrying, or whether to retry at all."},"status":{"type":"integer","description":"Repeated HTTP status code."},"docs":{"type":"string","format":"uri","description":"URL of the OpenAPI document."},"details":{"type":"array","description":"Field-level detail. Present on validation failures only.","items":{"type":"object","required":["field","issue"],"properties":{"field":{"type":"string","description":"Name of the offending request field or parameter."},"issue":{"type":"string","description":"What is wrong with it."}}}}}}}}}},"x-input-schema":{"type":"object","description":"Optional filters. Send an empty object for every industrie.","properties":{"slug":{"type":"string","maxLength":100,"description":"Return only the entry with this exact slug. Case-insensitive. An unknown slug is an empty collection, not an error."},"q":{"type":"string","maxLength":100,"description":"Case-insensitive substring searched across the name and description of each entry."},"limit":{"type":"integer","minimum":1,"maximum":100,"description":"Return at most this many entries after filtering. Omit for all of them; the lists are small."}},"additionalProperties":false}}},"/api/v1/pages":{"get":{"operationId":"listPages","summary":"List every page on the site","description":"The complete site index as JSON — the machine-readable twin of /llms.txt. Each entry carries both the HTML URL and the Markdown URL for the same content, so a follow-up fetch never needs a URL assembled by hand. Use this to discover what exists before fetching anything; narrow it with collection or q rather than pulling all hundred-plus entries.","tags":["Catalogue"],"parameters":[{"name":"collection","in":"query","required":false,"description":"Return only pages in this section — services, solutions, industries, technologies, hire, locations, insights, case-studies, home, or a legal page slug.","schema":{"type":"string","maxLength":100}},{"name":"q","in":"query","required":false,"description":"Case-insensitive substring matched against the page path.","schema":{"type":"string","maxLength":100}},{"name":"limit","in":"query","required":false,"description":"Return at most this many pages after filtering.","schema":{"type":"integer","minimum":1,"maximum":100}}],"responses":{"200":{"description":"List every page on the site: success.","headers":{"RateLimit-Policy":{"description":"Quota for this endpoint as a structured field, e.g. \"read\";q=120;w=60.","schema":{"type":"string"}},"RateLimit":{"description":"Remaining quota and seconds to reset, e.g. \"read\";r=118;t=57.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer"}},"X-API-Version":{"description":"Major version of the API that produced this response.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","title":"PageCollection","description":"The site index, after any filter.","required":["count","items"],"properties":{"count":{"type":"integer","description":"Number of pages returned, after filtering."},"items":{"type":"array","items":{"type":"object","title":"PageEntry","description":"One page on the site.","required":["path","collection","url","markdownUrl"],"properties":{"path":{"type":"string","description":"Site-relative path."},"collection":{"type":"string","description":"Section the page belongs to — services, insights, home, and so on."},"url":{"type":"string","format":"uri","description":"Absolute URL of the HTML page."},"markdownUrl":{"type":"string","format":"uri","description":"Absolute URL of the same content as Markdown."}}}}}}}}},"405":{"description":"Wrong HTTP method; this endpoint is read-only. Code: method_not_allowed.","headers":{"RateLimit-Policy":{"description":"Quota for this endpoint as a structured field, e.g. \"read\";q=120;w=60.","schema":{"type":"string"}},"RateLimit":{"description":"Remaining quota and seconds to reset, e.g. \"read\";r=118;t=57.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer"}},"X-API-Version":{"description":"Major version of the API that produced this response.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","title":"Error","description":"The response body every failure under /api/ returns. Branch on code; show error to a person; act on hint.","required":["error","code","hint","status","docs"],"properties":{"error":{"type":"string","description":"Human-readable message, safe to display to an end user."},"code":{"type":"string","enum":["malformed_json","validation_failed","method_not_allowed","route_not_found","rate_limited","delivery_failed","delivery_unavailable"],"description":"Stable machine-readable identifier for the failure."},"hint":{"type":"string","description":"What to change before retrying, or whether to retry at all."},"status":{"type":"integer","description":"Repeated HTTP status code."},"docs":{"type":"string","format":"uri","description":"URL of the OpenAPI document."},"details":{"type":"array","description":"Field-level detail. Present on validation failures only.","items":{"type":"object","required":["field","issue"],"properties":{"field":{"type":"string","description":"Name of the offending request field or parameter."},"issue":{"type":"string","description":"What is wrong with it."}}}}}}}}},"422":{"description":"A query parameter was rejected; details names it. Code: validation_failed.","headers":{"RateLimit-Policy":{"description":"Quota for this endpoint as a structured field, e.g. \"read\";q=120;w=60.","schema":{"type":"string"}},"RateLimit":{"description":"Remaining quota and seconds to reset, e.g. \"read\";r=118;t=57.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer"}},"X-API-Version":{"description":"Major version of the API that produced this response.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","title":"Error","description":"The response body every failure under /api/ returns. Branch on code; show error to a person; act on hint.","required":["error","code","hint","status","docs"],"properties":{"error":{"type":"string","description":"Human-readable message, safe to display to an end user."},"code":{"type":"string","enum":["malformed_json","validation_failed","method_not_allowed","route_not_found","rate_limited","delivery_failed","delivery_unavailable"],"description":"Stable machine-readable identifier for the failure."},"hint":{"type":"string","description":"What to change before retrying, or whether to retry at all."},"status":{"type":"integer","description":"Repeated HTTP status code."},"docs":{"type":"string","format":"uri","description":"URL of the OpenAPI document."},"details":{"type":"array","description":"Field-level detail. Present on validation failures only.","items":{"type":"object","required":["field","issue"],"properties":{"field":{"type":"string","description":"Name of the offending request field or parameter."},"issue":{"type":"string","description":"What is wrong with it."}}}}}}}}},"429":{"description":"Rate limit exceeded. Retry-After gives the seconds to wait and takes precedence over the RateLimit field.","headers":{"RateLimit-Policy":{"description":"Quota for this endpoint as a structured field, e.g. \"read\";q=120;w=60.","schema":{"type":"string"}},"RateLimit":{"description":"Remaining quota and seconds to reset, e.g. \"read\";r=118;t=57.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer"}},"X-API-Version":{"description":"Major version of the API that produced this response.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","title":"Error","description":"The response body every failure under /api/ returns. Branch on code; show error to a person; act on hint.","required":["error","code","hint","status","docs"],"properties":{"error":{"type":"string","description":"Human-readable message, safe to display to an end user."},"code":{"type":"string","enum":["malformed_json","validation_failed","method_not_allowed","route_not_found","rate_limited","delivery_failed","delivery_unavailable"],"description":"Stable machine-readable identifier for the failure."},"hint":{"type":"string","description":"What to change before retrying, or whether to retry at all."},"status":{"type":"integer","description":"Repeated HTTP status code."},"docs":{"type":"string","format":"uri","description":"URL of the OpenAPI document."},"details":{"type":"array","description":"Field-level detail. Present on validation failures only.","items":{"type":"object","required":["field","issue"],"properties":{"field":{"type":"string","description":"Name of the offending request field or parameter."},"issue":{"type":"string","description":"What is wrong with it."}}}}}}}}}},"x-input-schema":{"type":"object","description":"Optional filters. Send an empty object for the whole index.","properties":{"collection":{"type":"string","maxLength":100,"description":"Return only pages in this section — services, solutions, industries, technologies, hire, locations, insights, case-studies, home, or a legal page slug."},"q":{"type":"string","maxLength":100,"description":"Case-insensitive substring matched against the page path."},"limit":{"type":"integer","minimum":1,"maximum":100,"description":"Return at most this many pages after filtering."}},"additionalProperties":false}}},"/{path}":{"get":{"operationId":"getPage","summary":"Read any page as Markdown or HTML","description":"Every page on this site is available at its own URL in two representations. Send Accept: text/markdown for Markdown, anything else for HTML; appending .md to the path returns the same Markdown, and the home page is /index.md. Prefer this over the JSON catalogue when you want the actual content of a page rather than an index entry. Quality values are honoured, and an Accept header that rules out both representations gets a 406.","tags":["Content"],"parameters":[{"name":"path","in":"path","required":true,"description":"Page path without the leading slash. May contain slashes. Use an empty value for the home page.","schema":{"type":"string"},"example":"services/artificial-intelligence"},{"name":"Accept","in":"header","required":false,"description":"text/markdown for the Markdown representation; anything else, or omitted, for HTML. Quality values are honoured.","schema":{"type":"string","default":"text/html"},"example":"text/markdown"}],"responses":{"200":{"description":"The page, in the negotiated representation.","headers":{"Vary":{"description":"Includes Accept on the Markdown representation.","schema":{"type":"string"}},"Link":{"description":"rel=\"alternate\" pointing at the Markdown representation of this URL.","schema":{"type":"string"}}},"content":{"text/markdown":{"schema":{"type":"string","description":"The file, as text."}},"text/html":{"schema":{"type":"string","description":"The file, as text."}}}},"404":{"description":"No page is published at that path. The Markdown variant carries a short recovery map pointing at /llms.txt and /sitemap.xml.","content":{"text/markdown":{"schema":{"type":"string","description":"The file, as text."}},"text/html":{"schema":{"type":"string","description":"The file, as text."}}}},"406":{"description":"The Accept header ruled out both text/html and text/markdown.","content":{"text/plain":{"schema":{"type":"string"}}}}},"x-input-schema":{"type":"object","description":"The page to read.","properties":{"path":{"type":"string","description":"Site-relative path, with or without the leading slash — services/artificial-intelligence, /about, or an empty string for the home page. Paths come from listPages."},"format":{"type":"string","enum":["markdown","html"],"default":"markdown","description":"Which representation to request. markdown sends Accept: text/markdown; html sends the ordinary browser request."}},"required":["path"],"additionalProperties":false}}},"/api/v1/contact":{"post":{"operationId":"submitContactEnquiry","summary":"Submit a project brief","description":"Delivers an enquiry to the team, who reply within one business day. Succeeds when at least one configured destination accepts it. NOT IDEMPOTENT — a repeated request delivers a second copy to a human, so retry only on a 429 or a 5xx. Requires explicit consent:true from the person being represented; do not set it on someone's behalf without asking.","tags":["Enquiries"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","title":"ContactEnquiry","description":"A project brief.","required":["name","email","topic","message","consent"],"additionalProperties":false,"properties":{"name":{"type":"string","minLength":2,"maxLength":5000,"description":"Full name of the person enquiring."},"email":{"type":"string","format":"email","maxLength":5000,"description":"Address the reply goes to."},"company":{"type":"string","maxLength":5000,"description":"Optional. Company the person is enquiring on behalf of."},"phone":{"type":"string","maxLength":5000,"description":"Optional. Phone number, if they would rather be called."},"topic":{"type":"string","enum":["MVP development","SaaS platform build","Maintenance and support","AI voice agents","Cloud and DevOps","AI and data","Cybersecurity","Database management","Telecom engineering","IT staffing","Something else"],"description":"What the enquiry is about. Other values are accepted but will not match the team's routing."},"message":{"type":"string","minLength":20,"maxLength":5000,"description":"The brief itself."},"consent":{"type":"boolean","const":true,"description":"Must be true. Records that the sender agreed to be contacted about this enquiry."},"website":{"type":"string","description":"Spam honeypot. Leave absent or empty. A non-empty value is answered with 200 and discarded."}}},"example":{"name":"Dana Whitfield","email":"dana@example.com","company":"Example Logistics","phone":"","topic":"MVP development","message":"We need a driver-facing mobile app and a dispatch dashboard. Roughly 400 drivers today. Looking for a scoped first release.","consent":true}}}},"responses":{"200":{"description":"The enquiry was accepted and delivered to at least one destination.","headers":{"RateLimit-Policy":{"description":"Quota for this endpoint as a structured field, e.g. \"read\";q=120;w=60.","schema":{"type":"string"}},"RateLimit":{"description":"Remaining quota and seconds to reset, e.g. \"read\";r=118;t=57.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer"}},"X-API-Version":{"description":"Major version of the API that produced this response.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","title":"ContactAccepted","description":"The enquiry reached at least one destination. It does not mean a person has read it yet.","required":["ok"],"properties":{"ok":{"type":"boolean","const":true}}}}}},"400":{"description":"Body was not valid JSON. Code: malformed_json.","headers":{"RateLimit-Policy":{"description":"Quota for this endpoint as a structured field, e.g. \"read\";q=120;w=60.","schema":{"type":"string"}},"RateLimit":{"description":"Remaining quota and seconds to reset, e.g. \"read\";r=118;t=57.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer"}},"X-API-Version":{"description":"Major version of the API that produced this response.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","title":"Error","description":"The response body every failure under /api/ returns. Branch on code; show error to a person; act on hint.","required":["error","code","hint","status","docs"],"properties":{"error":{"type":"string","description":"Human-readable message, safe to display to an end user."},"code":{"type":"string","enum":["malformed_json","validation_failed","method_not_allowed","route_not_found","rate_limited","delivery_failed","delivery_unavailable"],"description":"Stable machine-readable identifier for the failure."},"hint":{"type":"string","description":"What to change before retrying, or whether to retry at all."},"status":{"type":"integer","description":"Repeated HTTP status code."},"docs":{"type":"string","format":"uri","description":"URL of the OpenAPI document."},"details":{"type":"array","description":"Field-level detail. Present on validation failures only.","items":{"type":"object","required":["field","issue"],"properties":{"field":{"type":"string","description":"Name of the offending request field or parameter."},"issue":{"type":"string","description":"What is wrong with it."}}}}}}}}},"405":{"description":"Wrong HTTP method; the Allow header names the right one. Code: method_not_allowed.","headers":{"RateLimit-Policy":{"description":"Quota for this endpoint as a structured field, e.g. \"read\";q=120;w=60.","schema":{"type":"string"}},"RateLimit":{"description":"Remaining quota and seconds to reset, e.g. \"read\";r=118;t=57.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer"}},"X-API-Version":{"description":"Major version of the API that produced this response.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","title":"Error","description":"The response body every failure under /api/ returns. Branch on code; show error to a person; act on hint.","required":["error","code","hint","status","docs"],"properties":{"error":{"type":"string","description":"Human-readable message, safe to display to an end user."},"code":{"type":"string","enum":["malformed_json","validation_failed","method_not_allowed","route_not_found","rate_limited","delivery_failed","delivery_unavailable"],"description":"Stable machine-readable identifier for the failure."},"hint":{"type":"string","description":"What to change before retrying, or whether to retry at all."},"status":{"type":"integer","description":"Repeated HTTP status code."},"docs":{"type":"string","format":"uri","description":"URL of the OpenAPI document."},"details":{"type":"array","description":"Field-level detail. Present on validation failures only.","items":{"type":"object","required":["field","issue"],"properties":{"field":{"type":"string","description":"Name of the offending request field or parameter."},"issue":{"type":"string","description":"What is wrong with it."}}}}}}}}},"422":{"description":"One or more fields failed validation; details names each one. Code: validation_failed.","headers":{"RateLimit-Policy":{"description":"Quota for this endpoint as a structured field, e.g. \"read\";q=120;w=60.","schema":{"type":"string"}},"RateLimit":{"description":"Remaining quota and seconds to reset, e.g. \"read\";r=118;t=57.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer"}},"X-API-Version":{"description":"Major version of the API that produced this response.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","title":"Error","description":"The response body every failure under /api/ returns. Branch on code; show error to a person; act on hint.","required":["error","code","hint","status","docs"],"properties":{"error":{"type":"string","description":"Human-readable message, safe to display to an end user."},"code":{"type":"string","enum":["malformed_json","validation_failed","method_not_allowed","route_not_found","rate_limited","delivery_failed","delivery_unavailable"],"description":"Stable machine-readable identifier for the failure."},"hint":{"type":"string","description":"What to change before retrying, or whether to retry at all."},"status":{"type":"integer","description":"Repeated HTTP status code."},"docs":{"type":"string","format":"uri","description":"URL of the OpenAPI document."},"details":{"type":"array","description":"Field-level detail. Present on validation failures only.","items":{"type":"object","required":["field","issue"],"properties":{"field":{"type":"string","description":"Name of the offending request field or parameter."},"issue":{"type":"string","description":"What is wrong with it."}}}}}}}}},"429":{"description":"Rate limit exceeded. Retry-After gives the seconds to wait and takes precedence over the RateLimit field.","headers":{"RateLimit-Policy":{"description":"Quota for this endpoint as a structured field, e.g. \"read\";q=120;w=60.","schema":{"type":"string"}},"RateLimit":{"description":"Remaining quota and seconds to reset, e.g. \"read\";r=118;t=57.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer"}},"X-API-Version":{"description":"Major version of the API that produced this response.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","title":"Error","description":"The response body every failure under /api/ returns. Branch on code; show error to a person; act on hint.","required":["error","code","hint","status","docs"],"properties":{"error":{"type":"string","description":"Human-readable message, safe to display to an end user."},"code":{"type":"string","enum":["malformed_json","validation_failed","method_not_allowed","route_not_found","rate_limited","delivery_failed","delivery_unavailable"],"description":"Stable machine-readable identifier for the failure."},"hint":{"type":"string","description":"What to change before retrying, or whether to retry at all."},"status":{"type":"integer","description":"Repeated HTTP status code."},"docs":{"type":"string","format":"uri","description":"URL of the OpenAPI document."},"details":{"type":"array","description":"Field-level detail. Present on validation failures only.","items":{"type":"object","required":["field","issue"],"properties":{"field":{"type":"string","description":"Name of the offending request field or parameter."},"issue":{"type":"string","description":"What is wrong with it."}}}}}}}}},"502":{"description":"Every delivery target failed. Safe to retry once. Code: delivery_failed.","headers":{"RateLimit-Policy":{"description":"Quota for this endpoint as a structured field, e.g. \"read\";q=120;w=60.","schema":{"type":"string"}},"RateLimit":{"description":"Remaining quota and seconds to reset, e.g. \"read\";r=118;t=57.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer"}},"X-API-Version":{"description":"Major version of the API that produced this response.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","title":"Error","description":"The response body every failure under /api/ returns. Branch on code; show error to a person; act on hint.","required":["error","code","hint","status","docs"],"properties":{"error":{"type":"string","description":"Human-readable message, safe to display to an end user."},"code":{"type":"string","enum":["malformed_json","validation_failed","method_not_allowed","route_not_found","rate_limited","delivery_failed","delivery_unavailable"],"description":"Stable machine-readable identifier for the failure."},"hint":{"type":"string","description":"What to change before retrying, or whether to retry at all."},"status":{"type":"integer","description":"Repeated HTTP status code."},"docs":{"type":"string","format":"uri","description":"URL of the OpenAPI document."},"details":{"type":"array","description":"Field-level detail. Present on validation failures only.","items":{"type":"object","required":["field","issue"],"properties":{"field":{"type":"string","description":"Name of the offending request field or parameter."},"issue":{"type":"string","description":"What is wrong with it."}}}}}}}}},"503":{"description":"No delivery target is configured. Do not retry; email instead. Code: delivery_unavailable.","headers":{"RateLimit-Policy":{"description":"Quota for this endpoint as a structured field, e.g. \"read\";q=120;w=60.","schema":{"type":"string"}},"RateLimit":{"description":"Remaining quota and seconds to reset, e.g. \"read\";r=118;t=57.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer"}},"X-API-Version":{"description":"Major version of the API that produced this response.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","title":"Error","description":"The response body every failure under /api/ returns. Branch on code; show error to a person; act on hint.","required":["error","code","hint","status","docs"],"properties":{"error":{"type":"string","description":"Human-readable message, safe to display to an end user."},"code":{"type":"string","enum":["malformed_json","validation_failed","method_not_allowed","route_not_found","rate_limited","delivery_failed","delivery_unavailable"],"description":"Stable machine-readable identifier for the failure."},"hint":{"type":"string","description":"What to change before retrying, or whether to retry at all."},"status":{"type":"integer","description":"Repeated HTTP status code."},"docs":{"type":"string","format":"uri","description":"URL of the OpenAPI document."},"details":{"type":"array","description":"Field-level detail. Present on validation failures only.","items":{"type":"object","required":["field","issue"],"properties":{"field":{"type":"string","description":"Name of the offending request field or parameter."},"issue":{"type":"string","description":"What is wrong with it."}}}}}}}}}},"x-input-schema":{"type":"object","title":"ContactEnquiry","description":"A project brief.","required":["name","email","topic","message","consent"],"additionalProperties":false,"properties":{"name":{"type":"string","minLength":2,"maxLength":5000,"description":"Full name of the person enquiring."},"email":{"type":"string","format":"email","maxLength":5000,"description":"Address the reply goes to."},"company":{"type":"string","maxLength":5000,"description":"Optional. Company the person is enquiring on behalf of."},"phone":{"type":"string","maxLength":5000,"description":"Optional. Phone number, if they would rather be called."},"topic":{"type":"string","enum":["MVP development","SaaS platform build","Maintenance and support","AI voice agents","Cloud and DevOps","AI and data","Cybersecurity","Database management","Telecom engineering","IT staffing","Something else"],"description":"What the enquiry is about. Other values are accepted but will not match the team's routing."},"message":{"type":"string","minLength":20,"maxLength":5000,"description":"The brief itself."},"consent":{"type":"boolean","const":true,"description":"Must be true. Records that the sender agreed to be contacted about this enquiry."},"website":{"type":"string","description":"Spam honeypot. Leave absent or empty. A non-empty value is answered with 200 and discarded."}}}}},"/api/contact":{"post":{"operationId":"submitContactEnquiryUnversioned","summary":"Submit a project brief (deprecated unversioned path)","description":"DEPRECATED — use submitContactEnquiry at /api/v1/contact instead. Behaviour is identical; this path exists only so that integrations written before v1 keep working. It answers until 2027-08-31, and every response carries Deprecation, Sunset, and Link headers.","tags":["Enquiries"],"deprecated":true,"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","title":"ContactEnquiry","description":"A project brief.","required":["name","email","topic","message","consent"],"additionalProperties":false,"properties":{"name":{"type":"string","minLength":2,"maxLength":5000,"description":"Full name of the person enquiring."},"email":{"type":"string","format":"email","maxLength":5000,"description":"Address the reply goes to."},"company":{"type":"string","maxLength":5000,"description":"Optional. Company the person is enquiring on behalf of."},"phone":{"type":"string","maxLength":5000,"description":"Optional. Phone number, if they would rather be called."},"topic":{"type":"string","enum":["MVP development","SaaS platform build","Maintenance and support","AI voice agents","Cloud and DevOps","AI and data","Cybersecurity","Database management","Telecom engineering","IT staffing","Something else"],"description":"What the enquiry is about. Other values are accepted but will not match the team's routing."},"message":{"type":"string","minLength":20,"maxLength":5000,"description":"The brief itself."},"consent":{"type":"boolean","const":true,"description":"Must be true. Records that the sender agreed to be contacted about this enquiry."},"website":{"type":"string","description":"Spam honeypot. Leave absent or empty. A non-empty value is answered with 200 and discarded."}}},"example":{"name":"Dana Whitfield","email":"dana@example.com","company":"Example Logistics","phone":"","topic":"MVP development","message":"We need a driver-facing mobile app and a dispatch dashboard. Roughly 400 drivers today. Looking for a scoped first release.","consent":true}}}},"responses":{"200":{"description":"The enquiry was accepted and delivered to at least one destination.","headers":{"RateLimit-Policy":{"description":"Quota for this endpoint as a structured field, e.g. \"read\";q=120;w=60.","schema":{"type":"string"}},"RateLimit":{"description":"Remaining quota and seconds to reset, e.g. \"read\";r=118;t=57.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer"}},"X-API-Version":{"description":"Major version of the API that produced this response.","schema":{"type":"string"}},"Deprecation":{"description":"RFC 9745 date stamp: when this endpoint became deprecated, as @<unix-seconds>.","schema":{"type":"string"}},"Sunset":{"description":"RFC 8594 HTTP-date: when this endpoint stops answering. Never earlier than Deprecation.","schema":{"type":"string"}},"Link":{"description":"Points at the deprecation policy (rel=\"deprecation\") and the replacement (rel=\"successor-version\").","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","title":"ContactAccepted","description":"The enquiry reached at least one destination. It does not mean a person has read it yet.","required":["ok"],"properties":{"ok":{"type":"boolean","const":true}}}}}},"400":{"description":"Body was not valid JSON. Code: malformed_json.","headers":{"RateLimit-Policy":{"description":"Quota for this endpoint as a structured field, e.g. \"read\";q=120;w=60.","schema":{"type":"string"}},"RateLimit":{"description":"Remaining quota and seconds to reset, e.g. \"read\";r=118;t=57.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer"}},"X-API-Version":{"description":"Major version of the API that produced this response.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","title":"Error","description":"The response body every failure under /api/ returns. Branch on code; show error to a person; act on hint.","required":["error","code","hint","status","docs"],"properties":{"error":{"type":"string","description":"Human-readable message, safe to display to an end user."},"code":{"type":"string","enum":["malformed_json","validation_failed","method_not_allowed","route_not_found","rate_limited","delivery_failed","delivery_unavailable"],"description":"Stable machine-readable identifier for the failure."},"hint":{"type":"string","description":"What to change before retrying, or whether to retry at all."},"status":{"type":"integer","description":"Repeated HTTP status code."},"docs":{"type":"string","format":"uri","description":"URL of the OpenAPI document."},"details":{"type":"array","description":"Field-level detail. Present on validation failures only.","items":{"type":"object","required":["field","issue"],"properties":{"field":{"type":"string","description":"Name of the offending request field or parameter."},"issue":{"type":"string","description":"What is wrong with it."}}}}}}}}},"405":{"description":"Wrong HTTP method; the Allow header names the right one. Code: method_not_allowed.","headers":{"RateLimit-Policy":{"description":"Quota for this endpoint as a structured field, e.g. \"read\";q=120;w=60.","schema":{"type":"string"}},"RateLimit":{"description":"Remaining quota and seconds to reset, e.g. \"read\";r=118;t=57.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer"}},"X-API-Version":{"description":"Major version of the API that produced this response.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","title":"Error","description":"The response body every failure under /api/ returns. Branch on code; show error to a person; act on hint.","required":["error","code","hint","status","docs"],"properties":{"error":{"type":"string","description":"Human-readable message, safe to display to an end user."},"code":{"type":"string","enum":["malformed_json","validation_failed","method_not_allowed","route_not_found","rate_limited","delivery_failed","delivery_unavailable"],"description":"Stable machine-readable identifier for the failure."},"hint":{"type":"string","description":"What to change before retrying, or whether to retry at all."},"status":{"type":"integer","description":"Repeated HTTP status code."},"docs":{"type":"string","format":"uri","description":"URL of the OpenAPI document."},"details":{"type":"array","description":"Field-level detail. Present on validation failures only.","items":{"type":"object","required":["field","issue"],"properties":{"field":{"type":"string","description":"Name of the offending request field or parameter."},"issue":{"type":"string","description":"What is wrong with it."}}}}}}}}},"422":{"description":"One or more fields failed validation; details names each one. Code: validation_failed.","headers":{"RateLimit-Policy":{"description":"Quota for this endpoint as a structured field, e.g. \"read\";q=120;w=60.","schema":{"type":"string"}},"RateLimit":{"description":"Remaining quota and seconds to reset, e.g. \"read\";r=118;t=57.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer"}},"X-API-Version":{"description":"Major version of the API that produced this response.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","title":"Error","description":"The response body every failure under /api/ returns. Branch on code; show error to a person; act on hint.","required":["error","code","hint","status","docs"],"properties":{"error":{"type":"string","description":"Human-readable message, safe to display to an end user."},"code":{"type":"string","enum":["malformed_json","validation_failed","method_not_allowed","route_not_found","rate_limited","delivery_failed","delivery_unavailable"],"description":"Stable machine-readable identifier for the failure."},"hint":{"type":"string","description":"What to change before retrying, or whether to retry at all."},"status":{"type":"integer","description":"Repeated HTTP status code."},"docs":{"type":"string","format":"uri","description":"URL of the OpenAPI document."},"details":{"type":"array","description":"Field-level detail. Present on validation failures only.","items":{"type":"object","required":["field","issue"],"properties":{"field":{"type":"string","description":"Name of the offending request field or parameter."},"issue":{"type":"string","description":"What is wrong with it."}}}}}}}}},"429":{"description":"Rate limit exceeded. Retry-After gives the seconds to wait and takes precedence over the RateLimit field.","headers":{"RateLimit-Policy":{"description":"Quota for this endpoint as a structured field, e.g. \"read\";q=120;w=60.","schema":{"type":"string"}},"RateLimit":{"description":"Remaining quota and seconds to reset, e.g. \"read\";r=118;t=57.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer"}},"X-API-Version":{"description":"Major version of the API that produced this response.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","title":"Error","description":"The response body every failure under /api/ returns. Branch on code; show error to a person; act on hint.","required":["error","code","hint","status","docs"],"properties":{"error":{"type":"string","description":"Human-readable message, safe to display to an end user."},"code":{"type":"string","enum":["malformed_json","validation_failed","method_not_allowed","route_not_found","rate_limited","delivery_failed","delivery_unavailable"],"description":"Stable machine-readable identifier for the failure."},"hint":{"type":"string","description":"What to change before retrying, or whether to retry at all."},"status":{"type":"integer","description":"Repeated HTTP status code."},"docs":{"type":"string","format":"uri","description":"URL of the OpenAPI document."},"details":{"type":"array","description":"Field-level detail. Present on validation failures only.","items":{"type":"object","required":["field","issue"],"properties":{"field":{"type":"string","description":"Name of the offending request field or parameter."},"issue":{"type":"string","description":"What is wrong with it."}}}}}}}}},"502":{"description":"Every delivery target failed. Safe to retry once. Code: delivery_failed.","headers":{"RateLimit-Policy":{"description":"Quota for this endpoint as a structured field, e.g. \"read\";q=120;w=60.","schema":{"type":"string"}},"RateLimit":{"description":"Remaining quota and seconds to reset, e.g. \"read\";r=118;t=57.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer"}},"X-API-Version":{"description":"Major version of the API that produced this response.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","title":"Error","description":"The response body every failure under /api/ returns. Branch on code; show error to a person; act on hint.","required":["error","code","hint","status","docs"],"properties":{"error":{"type":"string","description":"Human-readable message, safe to display to an end user."},"code":{"type":"string","enum":["malformed_json","validation_failed","method_not_allowed","route_not_found","rate_limited","delivery_failed","delivery_unavailable"],"description":"Stable machine-readable identifier for the failure."},"hint":{"type":"string","description":"What to change before retrying, or whether to retry at all."},"status":{"type":"integer","description":"Repeated HTTP status code."},"docs":{"type":"string","format":"uri","description":"URL of the OpenAPI document."},"details":{"type":"array","description":"Field-level detail. Present on validation failures only.","items":{"type":"object","required":["field","issue"],"properties":{"field":{"type":"string","description":"Name of the offending request field or parameter."},"issue":{"type":"string","description":"What is wrong with it."}}}}}}}}},"503":{"description":"No delivery target is configured. Do not retry; email instead. Code: delivery_unavailable.","headers":{"RateLimit-Policy":{"description":"Quota for this endpoint as a structured field, e.g. \"read\";q=120;w=60.","schema":{"type":"string"}},"RateLimit":{"description":"Remaining quota and seconds to reset, e.g. \"read\";r=118;t=57.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer"}},"X-API-Version":{"description":"Major version of the API that produced this response.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","title":"Error","description":"The response body every failure under /api/ returns. Branch on code; show error to a person; act on hint.","required":["error","code","hint","status","docs"],"properties":{"error":{"type":"string","description":"Human-readable message, safe to display to an end user."},"code":{"type":"string","enum":["malformed_json","validation_failed","method_not_allowed","route_not_found","rate_limited","delivery_failed","delivery_unavailable"],"description":"Stable machine-readable identifier for the failure."},"hint":{"type":"string","description":"What to change before retrying, or whether to retry at all."},"status":{"type":"integer","description":"Repeated HTTP status code."},"docs":{"type":"string","format":"uri","description":"URL of the OpenAPI document."},"details":{"type":"array","description":"Field-level detail. Present on validation failures only.","items":{"type":"object","required":["field","issue"],"properties":{"field":{"type":"string","description":"Name of the offending request field or parameter."},"issue":{"type":"string","description":"What is wrong with it."}}}}}}}}}},"x-input-schema":{"type":"object","title":"ContactEnquiry","description":"A project brief.","required":["name","email","topic","message","consent"],"additionalProperties":false,"properties":{"name":{"type":"string","minLength":2,"maxLength":5000,"description":"Full name of the person enquiring."},"email":{"type":"string","format":"email","maxLength":5000,"description":"Address the reply goes to."},"company":{"type":"string","maxLength":5000,"description":"Optional. Company the person is enquiring on behalf of."},"phone":{"type":"string","maxLength":5000,"description":"Optional. Phone number, if they would rather be called."},"topic":{"type":"string","enum":["MVP development","SaaS platform build","Maintenance and support","AI voice agents","Cloud and DevOps","AI and data","Cybersecurity","Database management","Telecom engineering","IT staffing","Something else"],"description":"What the enquiry is about. Other values are accepted but will not match the team's routing."},"message":{"type":"string","minLength":20,"maxLength":5000,"description":"The brief itself."},"consent":{"type":"boolean","const":true,"description":"Must be true. Records that the sender agreed to be contacted about this enquiry."},"website":{"type":"string","description":"Spam honeypot. Leave absent or empty. A non-empty value is answered with 200 and discarded."}}},"x-deprecation-policy":"https://www.centriconetechnologies.com/developers#deprecation-policy"}},"/mcp":{"post":{"operationId":"callMcpServer","summary":"Call the MCP server","description":"The Centricone Technologies MCP server, over the Model Context Protocol's Streamable HTTP transport. One JSON-RPC 2.0 request per POST; supported methods are initialize, notifications/initialized, tools/list, and tools/call. The tools are the operations flagged as tools in /tools.json. Point an MCP client at https://www.centriconetechnologies.com/mcp rather than calling this by hand.","tags":["Service"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"A single JSON-RPC 2.0 request.","properties":{"jsonrpc":{"type":"string","const":"2.0"},"id":{"type":["string","number","null"],"description":"Request id, echoed on the response. Absent on a notification."},"method":{"type":"string","enum":["initialize","notifications/initialized","tools/list","tools/call"],"description":"The JSON-RPC method to invoke."},"params":{"type":"object","description":"Method parameters. For tools/call: {name, arguments}, where name is a tool from tools/list."}},"required":["jsonrpc","method"],"additionalProperties":false},"example":{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"listServices","arguments":{"q":"cloud"}}}}}},"responses":{"200":{"description":"Call the MCP server: success.","content":{"application/json":{"schema":{"type":"object","title":"JsonRpcResponse","description":"A JSON-RPC 2.0 response. Either result or error is present, never both.","required":["jsonrpc"],"properties":{"jsonrpc":{"type":"string","const":"2.0"},"id":{"type":["string","number","null"]},"result":{"type":"object"},"error":{"type":"object","properties":{"code":{"type":"integer"},"message":{"type":"string"}}}}}}}}},"x-input-schema":{"type":"object","description":"A single JSON-RPC 2.0 request.","properties":{"jsonrpc":{"type":"string","const":"2.0"},"id":{"type":["string","number","null"],"description":"Request id, echoed on the response. Absent on a notification."},"method":{"type":"string","enum":["initialize","notifications/initialized","tools/list","tools/call"],"description":"The JSON-RPC method to invoke."},"params":{"type":"object","description":"Method parameters. For tools/call: {name, arguments}, where name is a tool from tools/list."}},"required":["jsonrpc","method"],"additionalProperties":false}}},"/openapi.json":{"get":{"operationId":"getOpenApiDocument","summary":"Fetch this OpenAPI document","description":"The machine-readable contract for everything above. Load it directly as a function-calling tool definition; /tools.json is the same operations already converted to tool definitions.","tags":["Content"],"responses":{"200":{"description":"Fetch this OpenAPI document: success.","content":{"application/json":{"schema":{"type":"object","title":"OpenApiDocument","description":"An OpenAPI 3.1 document.","required":["openapi","info","paths"],"properties":{"openapi":{"type":"string","examples":["3.1.0"]},"info":{"type":"object"},"paths":{"type":"object"},"components":{"type":"object"}}}}}}},"x-input-schema":{"type":"object","description":"No arguments.","properties":{},"additionalProperties":false}}},"/tools.json":{"get":{"operationId":"getToolManifest","summary":"Fetch the function-calling tool manifest","description":"Every callable operation as an LLM tool definition — name, description, and a complete JSON Schema for the arguments — in the shape the OpenAI, Anthropic, and Google function-calling APIs take. Load this if you would rather not convert https://www.centriconetechnologies.com/openapi.json yourself.","tags":["Content"],"responses":{"200":{"description":"Fetch the function-calling tool manifest: success.","content":{"application/json":{"schema":{"type":"object","title":"ToolManifest","required":["tools"],"properties":{"name":{"type":"string"},"description":{"type":"string"},"baseUrl":{"type":"string","format":"uri"},"authentication":{"type":"string"},"tools":{"type":"array","items":{"type":"object","required":["name","description","input_schema"],"properties":{"name":{"type":"string"},"description":{"type":"string"},"input_schema":{"type":"object"},"parameters":{"type":"object"},"endpoint":{"type":"object"}}}}}}}}}},"x-input-schema":{"type":"object","description":"No arguments.","properties":{},"additionalProperties":false}}},"/.well-known/api-catalog":{"get":{"operationId":"getApiCatalog","summary":"Fetch the API catalogue","description":"The RFC 9727 API catalogue: a linkset naming every developer resource this site publishes — the OpenAPI document, the developer portal, the tool manifest, the MCP server, and llms.txt. The conventional first stop when you know the domain and nothing else.","tags":["Content"],"responses":{"200":{"description":"Fetch the API catalogue: success.","content":{"application/linkset+json":{"schema":{"type":"object","title":"Linkset","description":"An RFC 9264 linkset.","required":["linkset"],"properties":{"linkset":{"type":"array","items":{"type":"object"}}}}}}}},"x-input-schema":{"type":"object","description":"No arguments.","properties":{},"additionalProperties":false}}},"/llms.txt":{"get":{"operationId":"getLlmsTxt","summary":"Fetch the site index for language models","description":"Every page on the site as a Markdown link list with a one-line summary each, per the llmstxt.org convention. listPages is the same index as JSON.","tags":["Content"],"responses":{"200":{"description":"Fetch the site index for language models: success.","content":{"text/plain":{"schema":{"type":"string","description":"The file, as text."}}}}},"x-input-schema":{"type":"object","description":"No arguments.","properties":{},"additionalProperties":false}}},"/sitemap.xml":{"get":{"operationId":"getSitemap","summary":"Fetch the XML sitemap","description":"Every indexable URL, with last-modified dates. listPages is the same set as JSON, with the Markdown address of each page attached.","tags":["Content"],"responses":{"200":{"description":"Fetch the XML sitemap: success.","content":{"application/xml":{"schema":{"type":"string","description":"The file, as text."}}}}},"x-input-schema":{"type":"object","description":"No arguments.","properties":{},"additionalProperties":false}}},"/robots.txt":{"get":{"operationId":"getRobotsTxt","summary":"Fetch the crawl rules","description":"Crawl directives and the sitemap reference. Everything is crawlable except /api/, which is a set of endpoints rather than pages.","tags":["Content"],"responses":{"200":{"description":"Fetch the crawl rules: success.","content":{"text/plain":{"schema":{"type":"string","description":"The file, as text."}}}}},"x-input-schema":{"type":"object","description":"No arguments.","properties":{},"additionalProperties":false}}}},"components":{"schemas":{"Error":{"type":"object","title":"Error","description":"The response body every failure under /api/ returns. Branch on code; show error to a person; act on hint.","required":["error","code","hint","status","docs"],"properties":{"error":{"type":"string","description":"Human-readable message, safe to display to an end user."},"code":{"type":"string","enum":["malformed_json","validation_failed","method_not_allowed","route_not_found","rate_limited","delivery_failed","delivery_unavailable"],"description":"Stable machine-readable identifier for the failure."},"hint":{"type":"string","description":"What to change before retrying, or whether to retry at all."},"status":{"type":"integer","description":"Repeated HTTP status code."},"docs":{"type":"string","format":"uri","description":"URL of the OpenAPI document."},"details":{"type":"array","description":"Field-level detail. Present on validation failures only.","items":{"type":"object","required":["field","issue"],"properties":{"field":{"type":"string","description":"Name of the offending request field or parameter."},"issue":{"type":"string","description":"What is wrong with it."}}}}}},"Health":{"type":"object","title":"Health","description":"Liveness and version.","required":["status","version","time"],"properties":{"status":{"type":"string","enum":["ok"],"description":"Always ok when the API answers at all."},"version":{"type":"string","description":"Major version of the API.","examples":["1"]},"time":{"type":"string","format":"date-time","description":"Server time, ISO 8601."}}},"CatalogEntry":{"type":"object","title":"CatalogEntry","description":"One service, engagement, or industry, with both addresses of its page.","required":["slug","name","description","path","url","markdownUrl"],"properties":{"slug":{"type":"string","description":"URL segment identifying this entry."},"name":{"type":"string","description":"Display name."},"description":{"type":"string","description":"One-sentence summary, as published on the page."},"path":{"type":"string","description":"Site-relative path of the page."},"url":{"type":"string","format":"uri","description":"Absolute URL of the HTML page."},"markdownUrl":{"type":"string","format":"uri","description":"Absolute URL of the same content as Markdown."}}},"CatalogCollection":{"type":"object","title":"CatalogCollection","description":"Catalogue entries. Unpaginated: count is the number of items in this response, after any filter.","required":["count","items"],"properties":{"count":{"type":"integer","description":"Number of items returned, after filtering."},"items":{"type":"array","items":{"type":"object","title":"CatalogEntry","description":"One service, engagement, or industry, with both addresses of its page.","required":["slug","name","description","path","url","markdownUrl"],"properties":{"slug":{"type":"string","description":"URL segment identifying this entry."},"name":{"type":"string","description":"Display name."},"description":{"type":"string","description":"One-sentence summary, as published on the page."},"path":{"type":"string","description":"Site-relative path of the page."},"url":{"type":"string","format":"uri","description":"Absolute URL of the HTML page."},"markdownUrl":{"type":"string","format":"uri","description":"Absolute URL of the same content as Markdown."}}}}}},"PageEntry":{"type":"object","title":"PageEntry","description":"One page on the site.","required":["path","collection","url","markdownUrl"],"properties":{"path":{"type":"string","description":"Site-relative path."},"collection":{"type":"string","description":"Section the page belongs to — services, insights, home, and so on."},"url":{"type":"string","format":"uri","description":"Absolute URL of the HTML page."},"markdownUrl":{"type":"string","format":"uri","description":"Absolute URL of the same content as Markdown."}}},"PageCollection":{"type":"object","title":"PageCollection","description":"The site index, after any filter.","required":["count","items"],"properties":{"count":{"type":"integer","description":"Number of pages returned, after filtering."},"items":{"type":"array","items":{"type":"object","title":"PageEntry","description":"One page on the site.","required":["path","collection","url","markdownUrl"],"properties":{"path":{"type":"string","description":"Site-relative path."},"collection":{"type":"string","description":"Section the page belongs to — services, insights, home, and so on."},"url":{"type":"string","format":"uri","description":"Absolute URL of the HTML page."},"markdownUrl":{"type":"string","format":"uri","description":"Absolute URL of the same content as Markdown."}}}}}},"ContactAccepted":{"type":"object","title":"ContactAccepted","description":"The enquiry reached at least one destination. It does not mean a person has read it yet.","required":["ok"],"properties":{"ok":{"type":"boolean","const":true}}},"ContactEnquiry":{"type":"object","title":"ContactEnquiry","description":"A project brief.","required":["name","email","topic","message","consent"],"additionalProperties":false,"properties":{"name":{"type":"string","minLength":2,"maxLength":5000,"description":"Full name of the person enquiring."},"email":{"type":"string","format":"email","maxLength":5000,"description":"Address the reply goes to."},"company":{"type":"string","maxLength":5000,"description":"Optional. Company the person is enquiring on behalf of."},"phone":{"type":"string","maxLength":5000,"description":"Optional. Phone number, if they would rather be called."},"topic":{"type":"string","enum":["MVP development","SaaS platform build","Maintenance and support","AI voice agents","Cloud and DevOps","AI and data","Cybersecurity","Database management","Telecom engineering","IT staffing","Something else"],"description":"What the enquiry is about. Other values are accepted but will not match the team's routing."},"message":{"type":"string","minLength":20,"maxLength":5000,"description":"The brief itself."},"consent":{"type":"boolean","const":true,"description":"Must be true. Records that the sender agreed to be contacted about this enquiry."},"website":{"type":"string","description":"Spam honeypot. Leave absent or empty. A non-empty value is answered with 200 and discarded."}}},"OpenApiDocument":{"type":"object","title":"OpenApiDocument","description":"An OpenAPI 3.1 document.","required":["openapi","info","paths"],"properties":{"openapi":{"type":"string","examples":["3.1.0"]},"info":{"type":"object"},"paths":{"type":"object"},"components":{"type":"object"}}},"ApiIndex":{"type":"object","title":"ApiIndex","description":"What lives under /api/v1, and where the machine-readable descriptions of it are.","required":["version","endpoints","documentation"],"properties":{"version":{"type":"string","description":"Major version of this API."},"status":{"type":"string","enum":["ok"]},"authentication":{"type":"string","description":"How to authenticate. Always \"none\" on this API."},"endpoints":{"type":"array","description":"Every operation this version publishes.","items":{"type":"object","required":["operationId","method","path","summary"],"properties":{"operationId":{"type":"string","description":"Stable id, matching /openapi.json and /tools.json."},"method":{"type":"string","description":"HTTP method."},"path":{"type":"string","description":"Site-relative path."},"url":{"type":"string","format":"uri","description":"Absolute URL."},"summary":{"type":"string","description":"One line on what it does."},"deprecated":{"type":"boolean","description":"True when the endpoint has a Sunset date."}}}},"rateLimit":{"type":"object","description":"The quotas enforced per client address.","properties":{"read":{"type":"object"},"write":{"type":"object"}}},"documentation":{"type":"object","description":"Where the descriptions of this API live.","properties":{"portal":{"type":"string","format":"uri"},"openapi":{"type":"string","format":"uri"},"tools":{"type":"string","format":"uri"},"mcp":{"type":"string","format":"uri"},"llmsTxt":{"type":"string","format":"uri"},"apiCatalog":{"type":"string","format":"uri"}}}}}}}}