{
  "openapi": "3.1.0",
  "info": {
    "title": "OpenAcquisitions Atlas API",
    "version": "1.0.0",
    "description": "Atlas verifies a US business name and state against OpenAcquisitions' corroborated 19.8M-row entity spine, built by cross-referencing state registries, federal loan and grant records, and other public filings. One endpoint, one header. API access is not self-serve yet — email hello@openacquisitions.co for a key."
  },
  "servers": [
    {
      "url": "https://api.openacquisitions.co",
      "description": "Production API host."
    }
  ],
  "security": [
    {
      "ApiKeyAuth": []
    }
  ],
  "paths": {
    "/api/health": {
      "get": {
        "operationId": "getHealth",
        "summary": "Health check",
        "description": "Unauthenticated health check. No API key required.",
        "security": [],
        "responses": {
          "200": {
            "description": "Service is healthy.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthResponse"
                },
                "example": {
                  "ok": true,
                  "service": "oa-atlas-api"
                }
              }
            }
          }
        }
      }
    },
    "/v1/verify": {
      "get": {
        "operationId": "verifyEntity",
        "summary": "Verify a business entity",
        "description": "Looks up a normalized (name, state) pair against the corroborated entity spine (atlas_canonical_entities). Read-only, no PII beyond public business registry data already sourced into the witness corpus.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "name",
            "in": "query",
            "required": true,
            "description": "The business name to look up, as written. Atlas normalizes it (case, punctuation, entity suffixes) before matching.",
            "schema": {
              "type": "string",
              "minLength": 1
            }
          },
          {
            "name": "state",
            "in": "query",
            "required": true,
            "description": "The state the business is registered in, as a 2-letter USPS code, e.g. FL, DE, CA.",
            "schema": {
              "type": "string",
              "minLength": 2,
              "maxLength": 2,
              "pattern": "^[A-Za-z]{2}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Lookup succeeded. Either a match (corroborated or unverified) or a not_found result — both return HTTP 200.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/VerifyMatchResponse"
                    },
                    {
                      "$ref": "#/components/schemas/VerifyNotFoundResponse"
                    }
                  ]
                },
                "examples": {
                  "corroborated": {
                    "summary": "Corroborated match",
                    "value": {
                      "status": "corroborated",
                      "display_name": "ACME WIDGETS LLC",
                      "state": "FL",
                      "source_count": 4,
                      "witness_count": 7,
                      "source_slugs": ["sunbiz", "irs-990", "ppp-loan-data", "sba-7a"],
                      "max_forgery_class": "B",
                      "independent_hard": true
                    }
                  },
                  "unverified": {
                    "summary": "Unverified match (found, below corroboration bar)",
                    "value": {
                      "status": "unverified",
                      "display_name": "ACME WIDGETS LLC",
                      "state": "FL",
                      "source_count": 1,
                      "witness_count": 1,
                      "source_slugs": ["sunbiz"],
                      "max_forgery_class": "D",
                      "independent_hard": false
                    }
                  },
                  "not_found": {
                    "summary": "No match",
                    "value": {
                      "status": "not_found",
                      "query": {
                        "name": "Acme Widgets LLC",
                        "state": "FL"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing or malformed query parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "missing_params": {
                    "summary": "name or state query param is missing",
                    "value": {
                      "error": "both 'name' and 'state' query params are required"
                    }
                  },
                  "bad_state": {
                    "summary": "state is not exactly a 2-letter USPS code",
                    "value": {
                      "error": "'state' must be a 2-letter USPS code"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "missing_key": {
                    "summary": "x-oa-api-key header is missing",
                    "value": {
                      "error": "missing x-oa-api-key header"
                    }
                  },
                  "invalid_key": {
                    "summary": "API key does not match an active row in atlas_api_keys",
                    "value": {
                      "error": "invalid or revoked api key"
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "x-oa-api-key",
        "description": "Required on all endpoints except /api/health. API access is not self-serve yet — email hello@openacquisitions.co to request a key."
      }
    },
    "schemas": {
      "HealthResponse": {
        "type": "object",
        "required": ["ok", "service"],
        "properties": {
          "ok": {
            "type": "boolean",
            "const": true
          },
          "service": {
            "type": "string",
            "const": "oa-atlas-api"
          }
        }
      },
      "VerifyMatchResponse": {
        "type": "object",
        "required": [
          "status",
          "display_name",
          "state",
          "source_count",
          "witness_count",
          "source_slugs",
          "max_forgery_class",
          "independent_hard"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": ["corroborated", "unverified"],
            "description": "corroborated = matched a verified entity in the spine; unverified = matched but rings below corroborated."
          },
          "display_name": {
            "type": "string",
            "description": "Canonical display name of the matched entity."
          },
          "state": {
            "type": "string",
            "description": "2-letter USPS state code of the matched entity."
          },
          "source_count": {
            "type": "integer",
            "minimum": 0,
            "description": "Number of independent public sources backing this entity."
          },
          "witness_count": {
            "type": "integer",
            "minimum": 0,
            "description": "Count of witness records associated with the entity."
          },
          "source_slugs": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Slugs identifying the public sources backing this entity (e.g. sunbiz, irs-990)."
          },
          "max_forgery_class": {
            "type": ["string", "null"],
            "description": "Highest fraud-risk classification observed across sources (letter grade)."
          },
          "independent_hard": {
            "type": "boolean",
            "description": "Whether at least one hard/authoritative independent source corroborates the entity."
          }
        }
      },
      "VerifyNotFoundResponse": {
        "type": "object",
        "required": ["status", "query"],
        "properties": {
          "status": {
            "type": "string",
            "const": "not_found"
          },
          "query": {
            "type": "object",
            "required": ["name", "state"],
            "properties": {
              "name": {
                "type": "string",
                "description": "The name query param as submitted (not normalized)."
              },
              "state": {
                "type": "string",
                "description": "The state query param, uppercased."
              }
            }
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "required": ["error"],
        "properties": {
          "error": {
            "type": "string"
          }
        }
      }
    }
  }
}
