{
  "openapi": "3.1.0",
  "info": {
    "title": "Archive Genocide API",
    "version": "1.0.0",
    "summary": "Read-only access to the archive's records of documented footage from Gaza and the West Bank.",
    "description": "Search and read the public records of the Archive Genocide footage archive: dates, captions (English and original language), sources, map locations and links to the footage. No key or account is needed and requests are not logged. Each visitor can make up to 120 requests a minute that reach the server (identical requests answered from the network cache within a few minutes are not counted); over that the API answers 429 with a Retry-After header. A search can be read 10,000 results deep; narrow it by date to go further. Captions come from the channels and journalists who posted the footage; a record documents what was posted and when, not a finding. Full guide and terms: https://archivegenocide.com/api-docs/",
    "termsOfService": "https://archivegenocide.com/api-docs/#terms",
    "contact": {
      "name": "Archive Genocide",
      "url": "https://archivegenocide.com/about.html"
    }
  },
  "servers": [
    {
      "url": "https://api.archivegenocide.com"
    }
  ],
  "externalDocs": {
    "description": "Full guide, examples and terms of use",
    "url": "https://archivegenocide.com/api-docs/"
  },
  "paths": {
    "/v1/clips": {
      "get": {
        "operationId": "searchClips",
        "summary": "Search and list clips",
        "description": "Returns a page of clips, newest first by default. All parameters are optional and can be combined. Unknown or repeated parameters are refused with 400.",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "description": "Words that must all appear in the caption, in English or the original language (Arabic works). Up to 200 characters. Search operators are treated as plain words.",
            "schema": {
              "type": "string",
              "maxLength": 200
            },
            "example": "hospital"
          },
          {
            "name": "type",
            "in": "query",
            "description": "Only videos or only photos.",
            "schema": {
              "type": "string",
              "enum": [
                "video",
                "photo"
              ]
            }
          },
          {
            "name": "from",
            "in": "query",
            "description": "Earliest posting date, YYYY-MM-DD, included.",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2023-11-01"
          },
          {
            "name": "to",
            "in": "query",
            "description": "Latest posting date, YYYY-MM-DD, included.",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2023-11-30"
          },
          {
            "name": "archive",
            "in": "query",
            "description": "One source collection, named exactly as returned by /v1/archives.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "has_geo",
            "in": "query",
            "description": "1 for clips with a map location, 0 for clips without.",
            "schema": {
              "type": "integer",
              "enum": [
                0,
                1
              ]
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "-date (newest first, default), date (oldest first) or id.",
            "schema": {
              "type": "string",
              "enum": [
                "-date",
                "date",
                "id"
              ],
              "default": "-date"
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page number, from 1. page times per_page may not exceed 10,000.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          },
          {
            "name": "per_page",
            "in": "query",
            "description": "Results per page.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of clips",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClipPage"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "414": {
            "$ref": "#/components/responses/BadRequest"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "503": {
            "$ref": "#/components/responses/Busy"
          }
        }
      }
    },
    "/v1/clips/{id}": {
      "get": {
        "operationId": "getClip",
        "summary": "One clip by id",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The clip's permanent id, as used on the site and in share links.",
            "schema": {
              "type": "integer",
              "minimum": 0
            },
            "example": 66454
          }
        ],
        "responses": {
          "200": {
            "description": "The clip",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Clip"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "410": {
            "description": "The clip was withdrawn from the archive. Delete any copy you keep.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "503": {
            "$ref": "#/components/responses/Busy"
          }
        }
      }
    },
    "/v1/archives": {
      "get": {
        "operationId": "listArchives",
        "summary": "Source collections and how many clips each holds",
        "responses": {
          "200": {
            "description": "Every source collection",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "archives"
                  ],
                  "properties": {
                    "archives": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "required": [
                          "name",
                          "clips"
                        ],
                        "properties": {
                          "name": {
                            "type": "string"
                          },
                          "clips": {
                            "type": "integer"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/withdrawn": {
      "get": {
        "operationId": "listWithdrawn",
        "summary": "Ids of clips withdrawn from the archive",
        "description": "If you keep copies of records, remove any clip whose id is in this list.",
        "responses": {
          "200": {
            "description": "Withdrawn ids",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ids"
                  ],
                  "properties": {
                    "ids": {
                      "type": "array",
                      "items": {
                        "type": "integer"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/v1/meta": {
      "get": {
        "operationId": "getMeta",
        "summary": "Counts and when the data was last built",
        "responses": {
          "200": {
            "description": "Dataset summary",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Meta"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Geo": {
        "type": [
          "object",
          "null"
        ],
        "description": "Where the clip is placed on the archive's Geolocation map, or null. precision_level: 1 = only the town or city the caption names (the point is the centre of that area); 2 = only the neighbourhood or camp the caption names; 3 = a building the caption names, not checked on the ground; 4 or more = an exact site, geolocated from the footage or from cited reporting (exact is true).",
        "required": [
          "lat",
          "lon",
          "precision_level",
          "exact"
        ],
        "properties": {
          "lat": {
            "type": "number"
          },
          "lon": {
            "type": "number"
          },
          "precision_level": {
            "type": "integer",
            "minimum": 1
          },
          "exact": {
            "type": "boolean"
          }
        }
      },
      "Clip": {
        "type": "object",
        "required": [
          "id",
          "type",
          "date",
          "caption",
          "caption_original",
          "source_archive",
          "media_url",
          "page_url",
          "geo"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "description": "Permanent id."
          },
          "type": {
            "type": "string",
            "enum": [
              "video",
              "photo"
            ]
          },
          "date": {
            "type": "string",
            "description": "When the source posted it, ISO 8601 with the source's time zone. The posting time, not necessarily the time of the event. Can be empty when unknown."
          },
          "duration": {
            "type": "string",
            "description": "Video length mm:ss; empty for photos."
          },
          "caption": {
            "type": "string",
            "description": "Caption in English (translated where needed)."
          },
          "caption_original": {
            "type": "string",
            "description": "Caption as the source wrote it."
          },
          "source_archive": {
            "type": "string",
            "description": "The collection the clip came from."
          },
          "source_post": {
            "type": "string",
            "description": "Link to the original post when known, else empty."
          },
          "media_url": {
            "type": "string",
            "format": "uri",
            "description": "The footage or photo."
          },
          "thumbnail_url": {
            "type": "string",
            "description": "Preview image, when there is one."
          },
          "page_url": {
            "type": "string",
            "format": "uri",
            "description": "A shareable page for the clip on the archive."
          },
          "confidence": {
            "type": "string",
            "enum": [
              "high",
              "medium",
              "low"
            ],
            "description": "Review status within the archive, not a judgement about whether an event happened."
          },
          "duplicate_of": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Id of an earlier copy of the same footage, or null."
          },
          "geo": {
            "$ref": "#/components/schemas/Geo"
          }
        }
      },
      "ClipPage": {
        "type": "object",
        "required": [
          "page",
          "per_page",
          "total",
          "total_is_lower_bound",
          "pages",
          "results"
        ],
        "properties": {
          "page": {
            "type": "integer"
          },
          "per_page": {
            "type": "integer"
          },
          "total": {
            "type": "integer",
            "description": "Matching clips, counted up to 10,000."
          },
          "total_is_lower_bound": {
            "type": "boolean",
            "description": "True when there are more than 10,000 matches; narrow by date to reach them."
          },
          "pages": {
            "type": "integer"
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Clip"
            }
          }
        }
      },
      "Meta": {
        "type": "object",
        "required": [
          "schema",
          "built_utc",
          "clips",
          "clips_with_location",
          "withdrawn"
        ],
        "properties": {
          "schema": {
            "type": "integer"
          },
          "built_utc": {
            "type": "string"
          },
          "clips": {
            "type": "integer"
          },
          "clips_with_location": {
            "type": "integer"
          },
          "withdrawn": {
            "type": "integer"
          },
          "terms": {
            "type": "string",
            "format": "uri"
          },
          "contact": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string",
            "description": "Plain-English explanation."
          }
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "A parameter is wrong, unknown or repeated, or the request is too long.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "NotFound": {
        "description": "No such clip or endpoint.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "TooManyRequests": {
        "description": "More than 120 requests in a minute. Wait the number of seconds in the Retry-After header.",
        "headers": {
          "Retry-After": {
            "schema": {
              "type": "integer"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Busy": {
        "description": "The service is busy or the query took too long. Wait and retry, or narrow the search.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    }
  }
}