{
  "openapi": "3.1.0",
  "info": {
    "title": "Local AI — Public Business API",
    "version": "1.0.0",
    "summary": "Read-only, unauthenticated access to Local AI's published business profile, services, capabilities and evidence.",
    "description": "A machine-readable view of facts that are already published on www.localai.systems.\n\n**Scope.** Everything here is public and read-only. There are no write\nendpoints, no authentication, and no access to client data. Nothing in\nthis API can commit Local AI to a price, a timeline or an appointment.\n\n**Data quality.** Fields that are not published on the website are\nomitted or null rather than estimated. `GET /api/v1/status` reports the\nknown gaps explicitly so a consumer can tell 'not published' from\n'endpoint broken'.\n\n**Client privacy.** Portfolio evidence is anonymized in this API by\npolicy. Named work is visible to humans at /work.\n\n**Versioning.** The path carries the major version. Additive changes\n(new fields, new endpoints) ship within v1; a breaking change would\nship as /api/v2 with v1 kept alive. `schema_version` on every payload\nreports the exact minor.\n\n**Last reviewed.** 2026-09-05.",
    "contact": {
      "name": "Local AI, LLC",
      "email": "yall@localai.systems",
      "url": "https://www.localai.systems/agent-access"
    },
    "termsOfService": "https://www.localai.systems/terms"
  },
  "security": [],
  "servers": [
    {
      "url": "https://www.localai.systems",
      "description": "Production"
    }
  ],
  "externalDocs": {
    "description": "Human-readable explanation of this API",
    "url": "https://www.localai.systems/agent-access"
  },
  "tags": [
    {
      "name": "profile",
      "description": "Identity, geography, contact, policies."
    },
    {
      "name": "offering",
      "description": "What Local AI does and for whom."
    },
    {
      "name": "meta",
      "description": "Liveness and data quality."
    }
  ],
  "paths": {
    "/api/v1/business": {
      "get": {
        "operationId": "getBusiness",
        "tags": [
          "profile"
        ],
        "summary": "The full public business profile",
        "description": "Identity, location and service area, contact routes, services, industries, policies, supported actions and data-quality reporting in one document.",
        "parameters": [
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Send the ETag from a previous response to receive 304 instead of a body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BusinessProfile"
                }
              }
            }
          },
          "304": {
            "description": "ETag matched `If-None-Match`; body omitted."
          },
          "429": {
            "description": "Too many requests. 60 per minute per client; responses are cacheable and change only on deploy.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "rate_limited",
                            "not_found",
                            "method_not_allowed"
                          ]
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    },
                    "schema_version": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/services": {
      "get": {
        "operationId": "listServices",
        "tags": [
          "offering"
        ],
        "summary": "The service pillars",
        "description": "The three pillars (AI, WEB, DESIGN) with their published offerings, in the order the website displays them.",
        "parameters": [
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Send the ETag from a previous response to receive 304 instead of a body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "schema_version",
                    "count",
                    "items"
                  ],
                  "properties": {
                    "schema_version": {
                      "type": "string",
                      "example": "1.0.0"
                    },
                    "count": {
                      "type": "integer"
                    },
                    "note": {
                      "type": "string"
                    },
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Service"
                      }
                    }
                  }
                }
              }
            }
          },
          "304": {
            "description": "ETag matched `If-None-Match`; body omitted."
          },
          "429": {
            "description": "Too many requests. 60 per minute per client; responses are cacheable and change only on deploy.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "rate_limited",
                            "not_found",
                            "method_not_allowed"
                          ]
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    },
                    "schema_version": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/services/{id}": {
      "get": {
        "operationId": "getService",
        "tags": [
          "offering"
        ],
        "summary": "One service pillar, with supporting evidence",
        "description": "The pillar plus the anonymized portfolio entries that substantiate it — the endpoint that answers 'have they actually shipped this?'.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Service pillar identifier.",
            "schema": {
              "type": "string",
              "enum": [
                "ai",
                "web",
                "design"
              ]
            }
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Send the ETag from a previous response to receive 304 instead of a body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Service"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "evidence": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Evidence"
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "304": {
            "description": "ETag matched `If-None-Match`; body omitted."
          },
          "404": {
            "description": "No resource with that identifier.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "rate_limited",
                            "not_found",
                            "method_not_allowed"
                          ]
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    },
                    "schema_version": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too many requests. 60 per minute per client; responses are cacheable and change only on deploy.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "rate_limited",
                            "not_found",
                            "method_not_allowed"
                          ]
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    },
                    "schema_version": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/capabilities": {
      "get": {
        "operationId": "listCapabilities",
        "tags": [
          "offering"
        ],
        "summary": "Individual offerings, flattened",
        "description": "Every offering across all pillars as a flat list — intended for matching a described business problem to a service.",
        "parameters": [
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Send the ETag from a previous response to receive 304 instead of a body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "schema_version",
                    "count",
                    "items"
                  ],
                  "properties": {
                    "schema_version": {
                      "type": "string",
                      "example": "1.0.0"
                    },
                    "count": {
                      "type": "integer"
                    },
                    "note": {
                      "type": "string"
                    },
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Capability"
                      }
                    }
                  }
                }
              }
            }
          },
          "304": {
            "description": "ETag matched `If-None-Match`; body omitted."
          },
          "429": {
            "description": "Too many requests. 60 per minute per client; responses are cacheable and change only on deploy.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "rate_limited",
                            "not_found",
                            "method_not_allowed"
                          ]
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    },
                    "schema_version": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/industries": {
      "get": {
        "operationId": "listIndustries",
        "tags": [
          "offering"
        ],
        "summary": "Industries with a published field guide",
        "description": "Only industries backed by a live guide are listed. Industries are never inferred from portfolio copy.",
        "parameters": [
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Send the ETag from a previous response to receive 304 instead of a body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "schema_version",
                    "count",
                    "items"
                  ],
                  "properties": {
                    "schema_version": {
                      "type": "string",
                      "example": "1.0.0"
                    },
                    "count": {
                      "type": "integer"
                    },
                    "note": {
                      "type": "string"
                    },
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Industry"
                      }
                    }
                  }
                }
              }
            }
          },
          "304": {
            "description": "ETag matched `If-None-Match`; body omitted."
          },
          "429": {
            "description": "Too many requests. 60 per minute per client; responses are cacheable and change only on deploy.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "rate_limited",
                            "not_found",
                            "method_not_allowed"
                          ]
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    },
                    "schema_version": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/evidence": {
      "get": {
        "operationId": "listEvidence",
        "tags": [
          "offering"
        ],
        "summary": "Anonymized portfolio evidence",
        "description": "Delivered work described by capability, category and technology. Client identities are withheld here by policy; named work is visible at /work.",
        "parameters": [
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Send the ETag from a previous response to receive 304 instead of a body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "schema_version",
                    "count",
                    "items"
                  ],
                  "properties": {
                    "schema_version": {
                      "type": "string",
                      "example": "1.0.0"
                    },
                    "count": {
                      "type": "integer"
                    },
                    "note": {
                      "type": "string"
                    },
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Evidence"
                      }
                    }
                  }
                }
              }
            }
          },
          "304": {
            "description": "ETag matched `If-None-Match`; body omitted."
          },
          "429": {
            "description": "Too many requests. 60 per minute per client; responses are cacheable and change only on deploy.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "rate_limited",
                            "not_found",
                            "method_not_allowed"
                          ]
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    },
                    "schema_version": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/faqs": {
      "get": {
        "operationId": "listFaqs",
        "tags": [
          "offering"
        ],
        "summary": "Published FAQs",
        "description": "Questions and answers taken verbatim from the field guides. Each item carries the URL of the page it appears on.",
        "parameters": [
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Send the ETag from a previous response to receive 304 instead of a body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "schema_version",
                    "count",
                    "items"
                  ],
                  "properties": {
                    "schema_version": {
                      "type": "string",
                      "example": "1.0.0"
                    },
                    "count": {
                      "type": "integer"
                    },
                    "note": {
                      "type": "string"
                    },
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Faq"
                      }
                    }
                  }
                }
              }
            }
          },
          "304": {
            "description": "ETag matched `If-None-Match`; body omitted."
          },
          "429": {
            "description": "Too many requests. 60 per minute per client; responses are cacheable and change only on deploy.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "rate_limited",
                            "not_found",
                            "method_not_allowed"
                          ]
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    },
                    "schema_version": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/status": {
      "get": {
        "operationId": "getStatus",
        "tags": [
          "meta"
        ],
        "summary": "Liveness and data-quality report",
        "description": "Confirms the layer is serving, and lists the fields Local AI has not published so a consumer can distinguish an omission from a fault.",
        "parameters": [
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "Send the ETag from a previous response to receive 304 instead of a body.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "304": {
            "description": "ETag matched `If-None-Match`; body omitted."
          },
          "429": {
            "description": "Too many requests. 60 per minute per client; responses are cacheable and change only on deploy.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "rate_limited",
                            "not_found",
                            "method_not_allowed"
                          ]
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    },
                    "schema_version": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Service": {
        "type": "object",
        "required": [
          "id",
          "name",
          "offerings",
          "status"
        ],
        "properties": {
          "id": {
            "type": "string",
            "enum": [
              "ai",
              "web",
              "design"
            ]
          },
          "name": {
            "type": "string"
          },
          "headline": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "offerings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "order": {
            "type": "integer"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "status": {
            "type": "string",
            "enum": [
              "active"
            ]
          },
          "delivery_modes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "evidence_categories": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "evidence_count": {
            "type": "integer"
          }
        },
        "example": {
          "id": "ai",
          "name": "AI",
          "headline": "The part most local businesses haven’t seen yet — and the part we can’t stop building.",
          "description": "Agents, automations, and assistants built around how your business actually runs — not a chatbot bolted onto a homepage. We start with the thing eating your time, then build the smallest system that takes it off your plate. This is the tech the big companies have been quietly running for years, finally within reach at our scale. And built right, you stop noticing it’s there — the busywork quietly stops being yours, and the week stops eating itself.",
          "offerings": [
            "AI agents + custom tools",
            "Business + workflow automation",
            "Internal knowledge bases",
            "AI voice agents",
            "Custom integrations between your tools",
            "Content engines trained on your voice",
            "Document + data extraction",
            "Dashboards",
            "AI strategy",
            "AI + tech education"
          ],
          "order": 1,
          "url": "https://www.localai.systems/services",
          "status": "active",
          "delivery_modes": [
            "onsite",
            "remote",
            "hybrid"
          ],
          "evidence_categories": [
            "ai-agents",
            "automations",
            "lab"
          ],
          "evidence_count": 13
        }
      },
      "Capability": {
        "type": "object",
        "required": [
          "label",
          "service_id"
        ],
        "properties": {
          "label": {
            "type": "string"
          },
          "service_id": {
            "type": "string"
          },
          "service_name": {
            "type": "string"
          }
        }
      },
      "Industry": {
        "type": "object",
        "required": [
          "id",
          "name"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "guide_url": {
            "type": "string",
            "format": "uri"
          },
          "has_published_guide": {
            "type": "boolean"
          }
        }
      },
      "Evidence": {
        "type": "object",
        "required": [
          "ref",
          "category"
        ],
        "description": "Anonymized by policy: no client name, slug or live URL is included.",
        "properties": {
          "ref": {
            "type": "string",
            "description": "Portfolio catalogue number."
          },
          "category": {
            "type": "string"
          },
          "category_label": {
            "type": "string"
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "capability_summary": {
            "type": "string"
          },
          "technologies": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "status": {
            "type": [
              "string",
              "null"
            ]
          },
          "url": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "Faq": {
        "type": "object",
        "required": [
          "id",
          "question",
          "answer"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "question": {
            "type": "string"
          },
          "answer": {
            "type": "string"
          },
          "industry_id": {
            "type": "string"
          },
          "industry_name": {
            "type": "string"
          },
          "source_url": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "Action": {
        "type": "object",
        "required": [
          "id",
          "status",
          "href",
          "method"
        ],
        "description": "A supported customer action. `planned` means the contract is published but no machine endpoint accepts it yet — the href is the human path.",
        "properties": {
          "id": {
            "type": "string"
          },
          "summary": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "available",
              "planned"
            ]
          },
          "href": {
            "type": "string",
            "format": "uri"
          },
          "method": {
            "type": "string",
            "enum": [
              "GET",
              "POST",
              "human"
            ]
          },
          "requires_human_confirmation": {
            "type": "boolean"
          }
        }
      },
      "BusinessProfile": {
        "type": "object",
        "required": [
          "schema_version",
          "last_updated",
          "canonical_url",
          "identity"
        ],
        "properties": {
          "schema_version": {
            "type": "string"
          },
          "last_updated": {
            "type": "string",
            "format": "date"
          },
          "canonical_url": {
            "type": "string",
            "format": "uri"
          },
          "identity": {
            "type": "object"
          },
          "location": {
            "type": "object"
          },
          "contact": {
            "type": "object"
          },
          "services": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Service"
            }
          },
          "industries": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Industry"
            }
          },
          "policies": {
            "type": "object"
          },
          "supported_actions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Action"
            }
          },
          "documentation": {
            "type": "object"
          },
          "data_quality": {
            "type": "object"
          }
        }
      },
      "Status": {
        "type": "object",
        "required": [
          "ok",
          "schema_version"
        ],
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "schema_version": {
            "type": "string"
          },
          "last_updated": {
            "type": "string",
            "format": "date"
          },
          "counts": {
            "type": "object"
          },
          "data_quality": {
            "type": "object"
          },
          "endpoints": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      }
    }
  }
}