{
  "openapi": "3.0.3",
  "info": {
    "title": "National AI Feed — Provider API",
    "version": "2.2.0",
    "description": "The National AI Feed Provider API. Machine clients authenticate with a long-lived API Key sent directly on every request via the X-API-Key header — there is no token-exchange step. Account profile and API Key management happen through the Provider dashboard (session login), not this programmatic surface, and are not documented here. Publishing to the National AI Feed is free for all approved GovTech Providers — there is no billing surface in this API.",
    "contact": {
      "name": "Aigistry",
      "email": "david@aigistry.com",
      "url": "https://aigistry.com"
    },
    "license": {
      "name": "Aigistry Terms & Conditions",
      "url": "https://aigistry.com/terms/"
    }
  },
  "servers": [
    { "url": "https://feed.aigistry.com/api", "description": "Production" }
  ],
  "tags": [
    { "name": "Public", "description": "No authentication required" },
    { "name": "Provider", "description": "Requires a Provider API Key" }
  ],
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "Long-lived, provider-scoped API Key. Sent directly on every request. Created and managed from the Provider dashboard (feed.aigistry.com/dashboard.html), not through this API."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "success": { "type": "boolean", "example": false },
          "error": { "type": "string", "example": "Invalid or disabled API key." }
        },
        "required": ["success", "error"]
      },
      "AuthorityRecord": {
        "type": "object",
        "properties": {
          "id": { "type": "integer", "example": 1 },
          "provider_id": { "type": "integer" },
          "provider_authority_id": {
            "type": "string",
            "nullable": true,
            "description": "The provider's own internal identifier for this record.",
            "example": "tampa-fl-001"
          },
          "authority_name": { "type": "string", "example": "City of Tampa" },
          "authority_type": {
            "type": "string",
            "enum": ["Federal", "State", "County", "City", "Town", "Village", "Public School District", "Public College", "Public University", "Special District", "Other"]
          },
          "website": { "type": "string", "format": "uri", "nullable": true },
          "city": { "type": "string", "nullable": true },
          "state_province": { "type": "string", "nullable": true },
          "country": { "type": "string", "example": "United States" },
          "status": { "type": "string", "enum": ["Active", "Suspended"] },
          "notes": { "type": "string", "nullable": true },
          "created_at": { "type": "string", "format": "date-time" },
          "updated_at": { "type": "string", "format": "date-time" }
        }
      },
      "AuthorityRecordCreate": {
        "type": "object",
        "required": ["authority_name", "authority_type"],
        "properties": {
          "provider_authority_id": { "type": "string", "nullable": true },
          "authority_name": { "type": "string" },
          "authority_type": {
            "type": "string",
            "enum": ["Federal", "State", "County", "City", "Town", "Village", "Public School District", "Public College", "Public University", "Special District", "Other"]
          },
          "website": { "type": "string", "format": "uri" },
          "city": { "type": "string" },
          "state_province": { "type": "string" },
          "country": { "type": "string", "default": "United States" }
        }
      },
      "AuthorityRecordUpdate": {
        "type": "object",
        "description": "All fields optional — send only what you want to change.",
        "properties": {
          "authority_name": { "type": "string" },
          "authority_type": {
            "type": "string",
            "enum": ["Federal", "State", "County", "City", "Town", "Village", "Public School District", "Public College", "Public University", "Special District", "Other"]
          },
          "website": { "type": "string", "format": "uri" },
          "city": { "type": "string" },
          "state_province": { "type": "string" },
          "country": { "type": "string" },
          "provider_authority_id": { "type": "string" }
        }
      },
      "Publication": {
        "type": "object",
        "properties": {
          "id": { "type": "integer", "example": 9042 },
          "authority_record_id": { "type": "integer" },
          "publication_title": { "type": "string", "example": "Temporary Road Closure" },
          "publication_body": { "type": "string" },
          "source_url": { "type": "string", "format": "uri", "nullable": true },
          "video_url": { "type": "string", "format": "uri", "nullable": true },
          "status": { "type": "string", "enum": ["Active", "Corrected"] },
          "submitted_at": { "type": "string", "format": "date-time" },
          "publication_hash": {
            "type": "string",
            "nullable": true,
            "description": "Empty string until signed. Populated by the feed-generation run, not at submission time."
          },
          "signature": { "type": "string", "nullable": true },
          "signing_key_id": { "type": "string", "nullable": true }
        }
      },
      "PublicationCreate": {
        "type": "object",
        "required": ["authority_record_id", "publication_title", "publication_body"],
        "properties": {
          "authority_record_id": { "type": "integer" },
          "publication_title": { "type": "string", "maxLength": 500 },
          "publication_body": { "type": "string" },
          "source_url": { "type": "string", "format": "uri" },
          "video_url": { "type": "string", "format": "uri" }
        }
      },
      "PublishAttempt": {
        "type": "object",
        "description": "A record of every publish.php call, successful or not — the underlying data behind the Publications tab's failure visibility in the Provider dashboard.",
        "properties": {
          "id": { "type": "integer" },
          "authority_record_id": {
            "type": "integer",
            "nullable": true,
            "description": "Null when the attempt failed before a valid Authority Record could be resolved."
          },
          "attempted_title": { "type": "string", "nullable": true },
          "success": { "type": "boolean" },
          "error_message": { "type": "string", "nullable": true },
          "publication_id": {
            "type": "integer",
            "nullable": true,
            "description": "Set only when success is true — links to the resulting Publication."
          },
          "occurred_at": { "type": "string", "format": "date-time" }
        }
      },
      "ActivityLogEntry": {
        "type": "object",
        "description": "One audit-trail entry for a mutating action taken on this Provider's account — Authority Record changes, API key creation/disablement.",
        "properties": {
          "id": { "type": "integer" },
          "action": {
            "type": "string",
            "example": "authority_record.suspended",
            "description": "Dot-separated target.verb string, e.g. authority_record.created, api_key.disabled."
          },
          "target_type": { "type": "string", "nullable": true, "example": "authority_record" },
          "target_id": { "type": "integer", "nullable": true },
          "details": {
            "type": "string",
            "nullable": true,
            "description": "Free-form JSON-encoded context specific to the action, e.g. {\"authority_name\":\"City of Tampa\"}."
          },
          "created_at": { "type": "string", "format": "date-time" }
        }
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "Missing, invalid, or disabled API Key.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "NotFound": {
        "description": "Resource not found, or not owned by the authenticated Provider.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "ValidationError": {
        "description": "Missing or invalid request fields.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      }
    }
  },
  "paths": {
    "/national.json": {
      "get": {
        "tags": ["Public"],
        "summary": "The public National AI Feed",
        "description": "The generated, signed, machine-readable feed. Rewritten every 5 minutes by the feed-generation cron, including a heartbeat update to generated_at even when there are no new Publications. Split into two arrays: 'registered' (cryptographically signed Publications submitted through the Provider API on behalf of verified Authority Records) and 'indexed' (records drawn directly from official government sources by Aigistry's own ingestion pipeline, not Provider-submitted, not signed with a Provider-linked Authority Record). Providers integrating through this API produce 'registered' records.",
        "servers": [{ "url": "https://feed.aigistry.com" }],
        "responses": {
          "200": {
            "description": "The current feed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "generated_at": { "type": "string", "format": "date-time" },
                    "registry": { "type": "string", "example": "National AI Feed" },
                    "record_count": { "type": "integer", "description": "registered_count + indexed_count." },
                    "registered_count": { "type": "integer" },
                    "indexed_count": { "type": "integer" },
                    "records": {
                      "type": "object",
                      "properties": {
                        "registered": {
                          "type": "array",
                          "description": "Provider-submitted, cryptographically signed Publications.",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "integer" },
                              "authority_name": { "type": "string" },
                              "authority_type": { "type": "string" },
                              "city": { "type": "string", "nullable": true },
                              "state_province": { "type": "string", "nullable": true },
                              "title": { "type": "string" },
                              "body": { "type": "string" },
                              "source_url": { "type": "string", "nullable": true },
                              "video_url": { "type": "string", "nullable": true },
                              "submitted_at": { "type": "string", "format": "date-time" },
                              "record_hash": { "type": "string" },
                              "signature": { "type": "string" },
                              "signature_algorithm": { "type": "string", "example": "Ed25519" },
                              "public_key_id": { "type": "string" }
                            }
                          }
                        },
                        "indexed": {
                          "type": "array",
                          "description": "Records drawn directly from official government sources by Aigistry's own ingestion pipeline. Not Provider-submitted and not covered in detail by this Provider-focused specification — field shape differs from 'registered' records (e.g. content_hash instead of record_hash, no cryptographic signature, source_feed_url and retrieved_at in place of Provider-specific fields).",
                          "items": { "type": "object" }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/public-key.json": {
      "get": {
        "tags": ["Public"],
        "summary": "Registry public key",
        "description": "The public half of the Ed25519 key used to sign every 'registered' record in the feed. Use this to independently verify a record's signature without contacting Aigistry.",
        "servers": [{ "url": "https://feed.aigistry.com" }],
        "responses": {
          "200": {
            "description": "The current public key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "public_key_id": { "type": "string", "example": "aigistry-registry-key-1" },
                    "algorithm": { "type": "string", "example": "Ed25519" },
                    "encoding": { "type": "string", "example": "hex" },
                    "public_key": { "type": "string" },
                    "registry": { "type": "string", "example": "National AI Feed" },
                    "issuer": { "type": "string", "example": "Aigistry, LLC" },
                    "published_at": { "type": "string", "format": "date-time" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/provider/authority-records.php": {
      "get": {
        "tags": ["Provider"],
        "summary": "List your Authority Records",
        "security": [{ "ApiKeyAuth": [] }],
        "parameters": [
          { "name": "status", "in": "query", "schema": { "type": "string", "enum": ["Active", "Suspended"] } },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "default": 50, "maximum": 200 } },
          { "name": "offset", "in": "query", "schema": { "type": "integer", "default": 0 } }
        ],
        "responses": {
          "200": {
            "description": "List of Authority Records.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "data": {
                      "type": "object",
                      "properties": {
                        "authority_records": { "type": "array", "items": { "$ref": "#/components/schemas/AuthorityRecord" } },
                        "total": { "type": "integer" }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      },
      "post": {
        "tags": ["Provider"],
        "summary": "Create (enroll) a new Authority Record",
        "security": [{ "ApiKeyAuth": [] }],
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AuthorityRecordCreate" } } }
        },
        "responses": {
          "201": {
            "description": "Authority Record created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "data": {
                      "type": "object",
                      "properties": {
                        "authority_record": { "$ref": "#/components/schemas/AuthorityRecord" }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "409": {
            "description": "provider_authority_id already in use for this Provider.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
          }
        }
      }
    },
    "/provider/authority-records.php?id={id}": {
      "get": {
        "tags": ["Provider"],
        "summary": "Get a single Authority Record",
        "security": [{ "ApiKeyAuth": [] }],
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }],
        "responses": {
          "200": {
            "description": "Authority Record.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "data": {
                      "type": "object",
                      "properties": {
                        "authority_record": { "$ref": "#/components/schemas/AuthorityRecord" }
                      }
                    }
                  }
                }
              }
            }
          },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      },
      "put": {
        "tags": ["Provider"],
        "summary": "Edit an Authority Record you own",
        "security": [{ "ApiKeyAuth": [] }],
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }],
        "requestBody": {
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AuthorityRecordUpdate" } } }
        },
        "responses": {
          "200": {
            "description": "Updated Authority Record.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "data": {
                      "type": "object",
                      "properties": {
                        "authority_record": { "$ref": "#/components/schemas/AuthorityRecord" }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/provider/authority-records.php?id={id}&action=suspend": {
      "post": {
        "tags": ["Provider"],
        "summary": "Suspend an Authority Record you own",
        "description": "No approval required — Providers control suspension of their own records directly, e.g. when a client agency ends its engagement.",
        "security": [{ "ApiKeyAuth": [] }],
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }],
        "responses": {
          "200": {
            "description": "Authority Record suspended.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "data": {
                      "type": "object",
                      "properties": {
                        "authority_record": { "$ref": "#/components/schemas/AuthorityRecord" }
                      }
                    }
                  }
                }
              }
            }
          },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/provider/authority-records.php?id={id}&action=reactivate": {
      "post": {
        "tags": ["Provider"],
        "summary": "Reactivate a suspended Authority Record you own",
        "security": [{ "ApiKeyAuth": [] }],
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }],
        "responses": {
          "200": {
            "description": "Authority Record reactivated.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "data": {
                      "type": "object",
                      "properties": {
                        "authority_record": { "$ref": "#/components/schemas/AuthorityRecord" }
                      }
                    }
                  }
                }
              }
            }
          },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/provider/publish.php": {
      "post": {
        "tags": ["Provider"],
        "summary": "Submit a new Publication",
        "description": "Publications are immutable once submitted. Corrections must be submitted as a new Publication, not an edit. Signing (publication_hash, signature) happens on the next feed-generation run, not at submission time. Every call — successful or not — is recorded in the publish-attempts log.",
        "security": [{ "ApiKeyAuth": [] }],
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PublicationCreate" } } }
        },
        "responses": {
          "201": {
            "description": "Publication accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "data": {
                      "type": "object",
                      "properties": {
                        "publication": { "$ref": "#/components/schemas/Publication" },
                        "note": { "type": "string", "example": "Will be signed and included on the next National AI Feed generation run." }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "403": {
            "description": "The Authority Record is not Active, or does not belong to the authenticated Provider.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
          },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/provider/publications.php": {
      "get": {
        "tags": ["Provider"],
        "summary": "List Publications submitted by your Provider",
        "description": "Only successful Publications appear here. For failed publish attempts, see publish-attempts.php.",
        "security": [{ "ApiKeyAuth": [] }],
        "parameters": [
          { "name": "authority_record_id", "in": "query", "schema": { "type": "integer" } },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "default": 50, "maximum": 200 } },
          { "name": "offset", "in": "query", "schema": { "type": "integer", "default": 0 } }
        ],
        "responses": {
          "200": {
            "description": "List of Publications.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "data": {
                      "type": "object",
                      "properties": {
                        "publications": { "type": "array", "items": { "$ref": "#/components/schemas/Publication" } },
                        "total": { "type": "integer" }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/provider/publish-attempts.php": {
      "get": {
        "tags": ["Provider"],
        "summary": "List every publish.php attempt, successful or failed",
        "description": "A full log of publish.php calls, including failures with their error reason — the data behind the Provider dashboard's merged Publications view. Use ?success=false to see only failures.",
        "security": [{ "ApiKeyAuth": [] }],
        "parameters": [
          { "name": "success", "in": "query", "schema": { "type": "string", "enum": ["true", "false"] } },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "default": 50, "maximum": 200 } },
          { "name": "offset", "in": "query", "schema": { "type": "integer", "default": 0 } }
        ],
        "responses": {
          "200": {
            "description": "List of publish attempts.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "data": {
                      "type": "object",
                      "properties": {
                        "publish_attempts": { "type": "array", "items": { "$ref": "#/components/schemas/PublishAttempt" } },
                        "total": { "type": "integer" }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" }
        }
      }
    },
    "/provider/activity-log.php": {
      "get": {
        "tags": ["Provider"],
        "summary": "List audit-trail entries for your own account",
        "description": "Every mutating action taken on this Provider's Authority Records and API keys — Authority Record creation/update/suspension/reactivation, API key creation/disablement.",
        "security": [{ "ApiKeyAuth": [] }],
        "parameters": [
          { "name": "action", "in": "query", "schema": { "type": "string" }, "description": "Exact match, e.g. authority_record.suspended." },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "default": 50, "maximum": 200 } },
          { "name": "offset", "in": "query", "schema": { "type": "integer", "default": 0 } }
        ],
        "responses": {
          "200": {
            "description": "List of activity log entries.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "data": {
                      "type": "object",
                      "properties": {
                        "activity": { "type": "array", "items": { "$ref": "#/components/schemas/ActivityLogEntry" } },
                        "total": { "type": "integer" }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
