{
  "openapi": "3.1.0",
  "info": {
    "title": "OpenGrant public preview API",
    "version": "1.0.0",
    "description": "Read-only public access to matching grant counts and the same three example grants shown to free visitors. The paid directory is not available through this API. Versioning and deprecation policy: endpoints use major URL versions; a replacement and retirement date will be announced at least 90 days before removal, with Deprecation and Sunset response headers during that notice period. V1 has no scheduled retirement.",
    "contact": {
      "url": "https://opengrant.co.uk/contact"
    },
    "license": {
      "name": "Source-specific licences",
      "url": "https://opengrant.co.uk/sources"
    },
    "x-deprecation-policy": "https://opengrant.co.uk/developers/deprecation"
  },
  "servers": [
    {
      "url": "https://opengrant.co.uk"
    }
  ],
  "externalDocs": {
    "description": "Developer guide and versioning policy",
    "url": "https://opengrant.co.uk/developers/deprecation"
  },
  "paths": {
    "/api": {
      "get": {
        "summary": "Discover the public preview API",
        "operationId": "getApiIndex",
        "responses": {
          "200": {
            "description": "API index",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "name",
                    "version",
                    "documentation",
                    "openapi",
                    "endpoints",
                    "access"
                  ],
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "version": {
                      "type": "string"
                    },
                    "documentation": {
                      "type": "string",
                      "format": "uri"
                    },
                    "openapi": {
                      "type": "string",
                      "format": "uri"
                    },
                    "endpoints": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "access": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "default": {
            "description": "JSON error with a stable code and human-readable message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/search/count": {
      "get": {
        "summary": "Count matching grants",
        "description": "Returns a matching count, not subscriber-only result records.",
        "operationId": "countGrants",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "description": "Keyword search",
            "schema": {
              "type": "string",
              "maxLength": 200
            }
          },
          {
            "name": "status",
            "in": "query",
            "description": "Comma-separated statuses, or all",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "geo",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "applicant",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "ftype",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "min",
            "in": "query",
            "schema": {
              "type": "number",
              "minimum": 0
            }
          },
          {
            "name": "max",
            "in": "query",
            "schema": {
              "type": "number",
              "minimum": 0
            }
          },
          {
            "name": "closes",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 366
            }
          },
          {
            "name": "source",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "eu",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "1"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Matching count",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CountResponse"
                }
              }
            }
          },
          "503": {
            "description": "Grant database temporarily unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "default": {
            "description": "JSON error with a stable code and human-readable message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/opportunities": {
      "get": {
        "summary": "List three public example grants",
        "description": "Examples are independent of the search count query.",
        "operationId": "listExampleGrants",
        "responses": {
          "200": {
            "description": "Public examples",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExampleList"
                }
              }
            }
          },
          "503": {
            "description": "Grant database temporarily unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "default": {
            "description": "JSON error with a stable code and human-readable message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "description": "Public examples per page (default 3)",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 3,
              "default": 3
            }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Zero-based offset into up to three public examples (default 0)",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 3,
              "default": 0
            }
          }
        ]
      }
    },
    "/api/v1/opportunities/{id}": {
      "get": {
        "summary": "Read a public example grant",
        "operationId": "getExampleGrant",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Public example",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/ExampleGrant"
                    },
                    "scope": {
                      "const": "public_example"
                    },
                    "pageUrl": {
                      "type": "string",
                      "format": "uri"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Opportunity is not a public example",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Grant database temporarily unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "default": {
            "description": "JSON error with a stable code and human-readable message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "CountResponse": {
        "type": "object",
        "required": [
          "total",
          "resultsUrl"
        ],
        "properties": {
          "total": {
            "type": "integer",
            "minimum": 0
          },
          "query": {
            "type": [
              "string",
              "null"
            ]
          },
          "filters": {
            "type": "object"
          },
          "resultsUrl": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "ExampleGrant": {
        "type": "object",
        "required": [
          "opportunityId",
          "title",
          "status",
          "source",
          "lastVerifiedAt"
        ],
        "properties": {
          "opportunityId": {
            "type": "string",
            "format": "uuid"
          },
          "title": {
            "type": "string"
          },
          "funderName": {
            "type": "string"
          },
          "summary": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": "string"
          },
          "nextDeadlineAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "amountMin": {
            "type": [
              "number",
              "null"
            ]
          },
          "amountMax": {
            "type": [
              "number",
              "null"
            ]
          },
          "currency": {
            "type": "string"
          },
          "source": {
            "type": "string"
          },
          "lastVerifiedAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "additionalProperties": true
      },
      "ExampleList": {
        "type": "object",
        "required": [
          "data",
          "count",
          "totalAvailable",
          "limit",
          "offset",
          "next",
          "scope"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ExampleGrant"
            },
            "maxItems": 3
          },
          "count": {
            "type": "integer",
            "minimum": 0,
            "maximum": 3
          },
          "scope": {
            "const": "public_examples"
          },
          "description": {
            "type": "string"
          },
          "fullDirectoryUrl": {
            "type": "string",
            "format": "uri"
          },
          "totalAvailable": {
            "type": "integer",
            "minimum": 0,
            "maximum": 3
          },
          "limit": {
            "type": "integer",
            "minimum": 1,
            "maximum": 3
          },
          "offset": {
            "type": "integer",
            "minimum": 0,
            "maximum": 3
          },
          "next": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "required": [
          "error",
          "documentation"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              }
            }
          },
          "documentation": {
            "type": "string",
            "format": "uri"
          }
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Invalid request parameter",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "NotPublic": {
        "description": "Opportunity is not a public example",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "Unavailable": {
        "description": "Grant database temporarily unavailable",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "ApiError": {
        "description": "JSON error with a stable code and human-readable message",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      }
    }
  }
}
