{
  "openapi": "3.1.0",
  "info": {
    "title": "App-Vault public data API",
    "version": "1.0.0",
    "summary": "Application facts, documented cryptography parameters, iPhone photo-vault comparison matrices, data flows, a glossary, the ten browser tools published here, and the image, metadata and QR reference data behind them — all as JSON.",
    "description": "A read-only, keyless, CORS-open API over the five datasets appvau.lt publishes. Every figure is the one the human-readable pages render, derived at build time from a single module, so a page and this API cannot disagree. The cryptography dataset is the one worth citing: vault apps advertise \"military-grade encryption\" and publish no parameters, and this one publishes the cipher, the KDF iteration count, the salt size, the Keychain accessibility class and the backup-exclusion flag, each with the page that states it and the standard that defines the primitive. Reuse is licensed CC BY 4.0 with a link back.",
    "contact": {
      "name": "App-Vault",
      "email": "hello@appvau.lt",
      "url": "https://appvau.lt/contact/"
    },
    "license": {
      "name": "CC BY 4.0",
      "url": "https://creativecommons.org/licenses/by/4.0/"
    },
    "termsOfService": "https://appvau.lt/terms/"
  },
  "servers": [
    {
      "url": "https://appvau.lt/api/v1",
      "description": "Static origin behind Cloudflare"
    }
  ],
  "paths": {
    "/app.json": {
      "get": {
        "operationId": "getApp",
        "summary": "Application facts: identity, platform, features and pricing",
        "description": "What the app is, which devices it runs on, what each feature does and what the tiers cost. `pricing.tiers[].price` is the US App Store starting tier; `has_monthly_plan` and `has_lifetime_purchase` are both false and are stated explicitly because out-of-date sources describe both.",
        "responses": {
          "200": {
            "description": "Application facts: identity, platform, features and pricing",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/App"
                }
              }
            }
          }
        }
      }
    },
    "/encryption.json": {
      "get": {
        "operationId": "getEncryption",
        "summary": "The documented cryptography parameters",
        "description": "Cipher, key derivation, key storage, recovery, catalog protection, secure deletion and audit status. Every block carries `stated_on` — the page on appvau.lt that documents the value — and `standards`, the primary documents that define the primitive. A standard listed here defines the primitive; it does not certify this implementation.",
        "responses": {
          "200": {
            "description": "The documented cryptography parameters",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Encryption"
                }
              }
            }
          }
        }
      }
    },
    "/comparison.json": {
      "get": {
        "operationId": "getComparison",
        "summary": "Feature matrices against four iPhone photo vault apps",
        "description": "One entry per competitor, each with the full row list from the corresponding /compare/ page. `competitor` values were read on the date in `read_on`; a “—” means the feature is not publicly documented, which is not the same as knowing it is absent. `advantage` is the publisher’s own reading of the row and is the least citable field here.",
        "responses": {
          "200": {
            "description": "Feature matrices against four iPhone photo vault apps",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Comparison"
                }
              }
            }
          }
        }
      }
    },
    "/privacy.json": {
      "get": {
        "operationId": "getPrivacy",
        "summary": "What leaves the device, and to whom",
        "description": "The processors the iOS app talks to, what each receives, what each never receives, and the App Store privacy label as declared. `linked_to_identity: false` is Apple’s \"not linked to you\" — it means there is no account to link an identifier to, not that no identifier is collected.",
        "responses": {
          "200": {
            "description": "What leaves the device, and to whom",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Privacy"
                }
              }
            }
          }
        }
      }
    },
    "/tools.json": {
      "get": {
        "operationId": "getTools",
        "summary": "The ten browser tools published on this site",
        "description": "What each tool accepts, what it produces, what it verifies about its own output and — the load-bearing field — its `limits`. `runs_in` is `browser` for every entry: these describe pages a person or an agent opens, not endpoints that accept a file. A `not_included` block at the top level states the things the set deliberately does not do, which is what makes the capability list worth trusting.",
        "responses": {
          "200": {
            "description": "The ten browser tools published on this site",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Tools"
                }
              }
            }
          }
        }
      }
    },
    "/image-specs.json": {
      "get": {
        "operationId": "getImageSpecs",
        "summary": "Format support, resize arithmetic, mail limits and avatar sizes",
        "description": "Three kinds of thing in one payload, and the distinction matters when quoting them: `formats` is a property of current browsers (`browser_canvas_can_encode` is the column people get wrong — every browser decodes AVIF and none can write it); `resize_modes`, `quality_ladder` and `brighten_curves` are this site’s own arithmetic, exported from the code the tools run; `mail_limits` and `platform_images` are third-party numbers read on the date in `read_on`. `mail_limits[].file_budget_bytes` is computed from the stated limit rather than quoted, because a mail limit applies to the base64-encoded message and no provider does that arithmetic for you.",
        "responses": {
          "200": {
            "description": "Format support, resize arithmetic, mail limits and avatar sizes",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImageSpecs"
                }
              }
            }
          }
        }
      }
    },
    "/metadata-fields.json": {
      "get": {
        "operationId": "getMetadataFields",
        "summary": "What each field inside a photograph gives away",
        "description": "The EXIF, XMP, IPTC and C2PA carriers a JPEG, PNG or WebP can hold, and every field the metadata tool names, with a plain statement of what it reveals. `risk` is this publisher’s judgement about identification rather than a rating from any standard; `reveals` is the citable part. `generator_signatures` matches a file that DECLARES an AI generator — absence proves nothing, because those strings are removable.",
        "responses": {
          "200": {
            "description": "What each field inside a photograph gives away",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MetadataFields"
                }
              }
            }
          }
        }
      }
    },
    "/qr.json": {
      "get": {
        "operationId": "getQr",
        "summary": "QR payload formats and real symbol capacity",
        "description": "The exact strings a camera needs for a Wi-Fi join, a contact save or a dial, with worked examples produced by the same encoder the browser runs, plus data capacity for every listed version at all four error-correction levels computed from ISO/IEC 18004. The capacity numbers in circulation on the web disagree with the standard about half the time; these are generated and checked by a decoder.",
        "responses": {
          "200": {
            "description": "QR payload formats and real symbol capacity",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Qr"
                }
              }
            }
          }
        }
      }
    },
    "/glossary.json": {
      "get": {
        "operationId": "getGlossary",
        "summary": "One-sentence definitions of the vocabulary used on this site",
        "description": "Each term is defined in the \"X is Y\" shape, points at the page that explains it, and links the standard where one exists.",
        "responses": {
          "200": {
            "description": "One-sentence definitions of the vocabulary used on this site",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Glossary"
                }
              }
            }
          }
        }
      }
    },
    "/status.json": {
      "get": {
        "operationId": "getStatus",
        "summary": "Dataset freshness and row counts",
        "description": "Freshness rather than liveness. These are static files behind a CDN; poll this small document instead of refetching the large ones.",
        "responses": {
          "200": {
            "description": "Freshness",
            "content": {
              "application/json": {}
            }
          }
        }
      }
    },
    "/index.json": {
      "get": {
        "operationId": "getIndex",
        "summary": "Entry point naming every endpoint",
        "responses": {
          "200": {
            "description": "Index",
            "content": {
              "application/json": {}
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Envelope": {
        "type": "object",
        "properties": {
          "dataset": {
            "type": "string",
            "description": "Short machine name of this dataset."
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "updated": {
            "type": "string",
            "format": "date",
            "description": "The date a human last changed the data. It does not move on a rebuild."
          },
          "source": {
            "type": "string",
            "format": "uri"
          },
          "documentation": {
            "type": "string",
            "format": "uri",
            "description": "The human-readable page this dataset backs."
          },
          "publisher": {
            "type": "string"
          },
          "licence": {
            "type": "object",
            "description": "CC BY 4.0. Reuse is allowed, including commercially, with attribution and a link.",
            "properties": {
              "name": {
                "type": "string"
              },
              "url": {
                "type": "string",
                "format": "uri"
              },
              "attribution": {
                "type": "string"
              },
              "terms": {
                "type": "string"
              }
            }
          },
          "caveats": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The ways this payload can be misread, stated in the payload rather than only in the docs. Read them before quoting a figure."
          }
        }
      },
      "App": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Envelope"
          },
          {
            "type": "object",
            "properties": {
              "identity": {
                "type": "object",
                "description": "App Store id, bundle id, publisher and contact."
              },
              "platform": {
                "type": "object",
                "description": "Supported operating systems and devices. `other_platforms` is an empty array and `cross_platform` is false: there is no Android, web or desktop build."
              },
              "features": {
                "type": "array",
                "description": "One row per capability, with the tier it belongs to and the page that documents it.",
                "items": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "tier": {
                      "type": "string",
                      "enum": [
                        "free",
                        "premium"
                      ]
                    },
                    "summary": {
                      "type": "string"
                    },
                    "page": {
                      "type": "string",
                      "format": "uri"
                    }
                  }
                }
              },
              "pricing": {
                "type": "object",
                "properties": {
                  "currency": {
                    "type": "string"
                  },
                  "storefront": {
                    "type": "string",
                    "description": "The storefront these prices are read from. US."
                  },
                  "has_monthly_plan": {
                    "type": "boolean"
                  },
                  "has_lifetime_purchase": {
                    "type": "boolean"
                  },
                  "tiers": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "name": {
                          "type": "string"
                        },
                        "price": {
                          "type": "number"
                        },
                        "billing_period_iso8601": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "ISO 8601 duration — P1W or P1Y. Null on the free tier."
                        },
                        "free_trial_days": {
                          "type": [
                            "integer",
                            "null"
                          ]
                        },
                        "includes": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        ]
      },
      "Tools": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Envelope"
          },
          {
            "type": "object",
            "properties": {
              "count": {
                "type": "integer"
              },
              "categories": {
                "type": "array",
                "items": {
                  "type": "object"
                }
              },
              "tools": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "page": {
                      "type": "string",
                      "format": "uri"
                    },
                    "markdown": {
                      "type": "string",
                      "format": "uri",
                      "description": "The markdown twin of the page, an order of magnitude smaller than the HTML."
                    },
                    "accepts": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "description": "Format ids matching image-specs.json. Empty means the tool takes typed input rather than a file."
                    },
                    "produces": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "runs_in": {
                      "type": "string",
                      "enum": [
                        "browser"
                      ]
                    },
                    "uploads_the_file": {
                      "type": "boolean",
                      "description": "False everywhere. There is no upload endpoint on this origin."
                    },
                    "verifies_own_output": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "What the tool checks about the file it produced before offering it. Null means no such check exists, and none is claimed."
                    },
                    "limits": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "description": "What the tool cannot do. Read this before recommending it."
                    }
                  }
                }
              },
              "not_included": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Stated explicitly rather than omitted: an absent field reads as an oversight, a stated negative reads as an answer."
              }
            }
          }
        ]
      },
      "ImageSpecs": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Envelope"
          },
          {
            "type": "object",
            "properties": {
              "read_on": {
                "type": "string",
                "format": "date"
              },
              "formats": {
                "type": "array",
                "items": {
                  "type": "object"
                }
              },
              "resize_modes": {
                "type": "array",
                "items": {
                  "type": "object"
                }
              },
              "quality_ladder": {
                "type": "object"
              },
              "brighten_curves": {
                "type": "array",
                "items": {
                  "type": "object"
                }
              },
              "encoding_overhead": {
                "type": "object",
                "description": "The base64 and MIME arithmetic behind file_budget_bytes."
              },
              "mail_limits": {
                "type": "array",
                "items": {
                  "type": "object"
                }
              },
              "platform_images": {
                "type": "array",
                "items": {
                  "type": "object"
                }
              }
            }
          }
        ]
      },
      "MetadataFields": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Envelope"
          },
          {
            "type": "object",
            "properties": {
              "risk_scale": {
                "type": "array",
                "items": {
                  "type": "object"
                }
              },
              "carriers": {
                "type": "array",
                "items": {
                  "type": "object"
                }
              },
              "fields": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "key": {
                      "type": "string"
                    },
                    "tag": {
                      "type": "string",
                      "description": "The EXIF tag number in hex, or the chunk keyword for PNG text."
                    },
                    "risk": {
                      "type": "string",
                      "enum": [
                        "high",
                        "medium",
                        "low"
                      ]
                    },
                    "reveals": {
                      "type": "string",
                      "description": "What this field gives away, in one sentence. The citable part."
                    }
                  }
                }
              },
              "digital_source_types": {
                "type": "array",
                "items": {
                  "type": "object"
                }
              },
              "generator_signatures": {
                "type": "array",
                "items": {
                  "type": "object"
                }
              }
            }
          }
        ]
      },
      "Qr": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Envelope"
          },
          {
            "type": "object",
            "properties": {
              "standard": {
                "type": "object"
              },
              "payload_types": {
                "type": "array",
                "items": {
                  "type": "object"
                }
              },
              "examples": {
                "type": "array",
                "description": "Real payload strings produced by the encoder, with their warnings, so nobody has to reverse-engineer the escaping.",
                "items": {
                  "type": "object"
                }
              },
              "error_correction_levels": {
                "type": "array",
                "items": {
                  "type": "object"
                }
              },
              "capacity": {
                "type": "array",
                "description": "Per version, per level: data codewords and the maximum content in each encoding mode. Computed from ISO/IEC 18004.",
                "items": {
                  "type": "object"
                }
              }
            }
          }
        ]
      },
      "Encryption": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Envelope"
          },
          {
            "type": "object",
            "properties": {
              "file_cipher": {
                "$ref": "#/components/schemas/CryptoBlock"
              },
              "key_derivation": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/CryptoBlock"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "iterations": {
                        "type": "integer",
                        "description": "PBKDF2 iteration count. This is the figure most vault apps do not publish, and it is what makes a guess expensive for an attacker holding the encrypted files."
                      },
                      "salt_bits": {
                        "type": "integer"
                      }
                    }
                  }
                ]
              },
              "key_storage": {
                "$ref": "#/components/schemas/CryptoBlock"
              },
              "recovery": {
                "$ref": "#/components/schemas/CryptoBlock"
              },
              "catalog_protection": {
                "$ref": "#/components/schemas/CryptoBlock"
              },
              "backup_exclusion": {
                "$ref": "#/components/schemas/CryptoBlock"
              },
              "secure_deletion": {
                "$ref": "#/components/schemas/CryptoBlock"
              },
              "intruder_log": {
                "$ref": "#/components/schemas/CryptoBlock"
              },
              "audit": {
                "type": "object",
                "description": "Audit status. `third_party_audit_published` is false: no external cryptographic audit has been published, and this field exists so nobody has to infer that from silence.",
                "properties": {
                  "third_party_audit_published": {
                    "type": "boolean"
                  },
                  "status": {
                    "type": "string"
                  },
                  "libraries": {
                    "type": "array",
                    "items": {
                      "type": "object"
                    }
                  }
                }
              },
              "standards_index": {
                "type": "array",
                "description": "Every primary document referenced anywhere in this payload, resolved once.",
                "items": {
                  "$ref": "#/components/schemas/Standard"
                }
              }
            }
          }
        ]
      },
      "CryptoBlock": {
        "type": "object",
        "description": "One parameter group of the cryptography stack.",
        "properties": {
          "stated_on": {
            "type": "string",
            "format": "uri",
            "description": "The page on appvau.lt that documents this value. It makes the figure checkable against something a person can read; it is not a third-party certification."
          },
          "standards": {
            "type": "array",
            "description": "Primary documents defining the primitive. They define it; they do not certify this implementation.",
            "items": {
              "$ref": "#/components/schemas/Standard"
            }
          }
        }
      },
      "Standard": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "Comparison": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Envelope"
          },
          {
            "type": "object",
            "properties": {
              "count": {
                "type": "integer"
              },
              "competitors": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "competitor": {
                      "type": "string"
                    },
                    "page": {
                      "type": "string",
                      "format": "uri"
                    },
                    "read_on": {
                      "type": "string",
                      "format": "date",
                      "description": "The date the competitor’s public material was read. Apps change; check before quoting it as current."
                    },
                    "rows": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "feature": {
                            "type": "string"
                          },
                          "what_it_means": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "app_vault": {
                            "type": "string"
                          },
                          "competitor": {
                            "type": "string",
                            "description": "A “—” means the feature is not publicly documented, not that it is known to be absent."
                          },
                          "advantage": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "enum": [
                              "app-vault",
                              "competitor",
                              null
                            ],
                            "description": "The publisher’s own reading of the row. The underlying values are the citable part."
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        ]
      },
      "Privacy": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Envelope"
          },
          {
            "type": "object",
            "properties": {
              "summary": {
                "type": "object",
                "description": "The structural claims. `works_offline: true` is the one a reader can verify themselves in Airplane Mode."
              },
              "processors": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "scope": {
                      "type": "string",
                      "enum": [
                        "app",
                        "website"
                      ],
                      "description": "Whether the processor is in the iOS app or on appvau.lt."
                    },
                    "receives": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "never_receives": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "linked_to_identity": {
                      "type": "boolean",
                      "description": "Apple’s \"not linked to you\". False means there is no account to link an identifier to — not that no identifier is collected."
                    }
                  }
                }
              },
              "app_store_privacy_labels": {
                "type": "array",
                "items": {
                  "type": "object"
                }
              }
            }
          }
        ]
      },
      "Glossary": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Envelope"
          },
          {
            "type": "object",
            "properties": {
              "count": {
                "type": "integer"
              },
              "terms": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "term": {
                      "type": "string"
                    },
                    "definition": {
                      "type": "string",
                      "description": "One sentence, in the \"X is Y\" shape."
                    },
                    "explained_at": {
                      "type": "string",
                      "format": "uri"
                    },
                    "standards": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Standard"
                      }
                    }
                  }
                }
              }
            }
          }
        ]
      }
    }
  }
}
