Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/sxzz/midden. Archive posts and media across platforms, with tenant accounts and Telegram access
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499openapi: 3.0.3info: title: Monitor Collection API version: 0.1.0 description: Tenant-scoped collections. Telegram Mini App sessions browse saved content only; Bearer clients retain existing public-content access.servers: - url: http://localhost:8080security: - bearerAuth: [] - webSession: []paths: /v1/auth/telegram: post: summary: Exchange signed Telegram initData for a 12-hour HttpOnly session description: Requires configured web_app_url, matching Origin, valid bot signature and auth_date within five minutes (30 seconds future tolerance). Resolves the same tenant as the Bot. security: [] requestBody: required: true content: application/json: schema: type: object required: [init_data] properties: init_data: { type: string } responses: "200": description: Session created; sets __Host-midden cookie (Secure, HttpOnly, SameSite=None, Path=/) content: application/json: schema: { type: object, properties: { tenant_id: { type: string, format: uuid } }, } "401": { $ref: "#/components/responses/Unauthorized" } "403": { description: Origin does not match web_app_url } "404": { description: Mini App disabled } /v1/session: get: summary: Read the authenticated tenant responses: "200": description: Current identity content: application/json: schema: { type: object, properties: { tenant_id: { type: string, format: uuid } }, } "401": { $ref: "#/components/responses/Unauthorized" } delete: summary: Revoke the current browser session and clear its cookie responses: "204": { description: Session revoked } "403": { description: Invalid Origin for a cookie-authenticated write } /v1/collections/{id}/availability: get: summary: Read capture availability for this saved collection's adapter parameters: [{ $ref: "#/components/parameters/ID" }] responses: "200": description: Background discovery status (may lag by 15 seconds plus discovery time) content: application/json: schema: { type: object, properties: { available: { type: boolean } } } "404": { $ref: "#/components/responses/NotFound" } /v1/collections/{id}/revisions: get: summary: List retained versions of a saved collection, newest first parameters: - { $ref: "#/components/parameters/ID" } - { in: query, name: cursor, schema: { type: string } } responses: "200": description: At most 20 versions; next_cursor is omitted at the end content: application/json: schema: type: object properties: items: type: array items: type: object properties: id: { type: string, format: uuid } created_at: { type: string, format: date-time } next_cursor: { type: string } "404": { $ref: "#/components/responses/NotFound" } /v1/collections/{id}/revisions/{revision_id}: get: summary: Read one retained version with its original entity and media snapshots parameters: - { $ref: "#/components/parameters/ID" } - { in: path, name: revision_id, required: true, schema: { type: string, format: uuid }, } responses: "200": description: Saved collection version content: application/json: schema: { $ref: "#/components/schemas/Collection" } "404": { $ref: "#/components/responses/NotFound" } /v1/captures: post: summary: Submit an X URL or refresh an existing collection parameters: - in: header name: Idempotency-Key schema: { type: string, maxLength: 200 } requestBody: required: true content: application/json: schema: type: object additionalProperties: false properties: url: { type: string, format: uri } refresh_id: { type: string, format: uuid } provider_id: { type: string, enum: [fxtwitter, x-session], description: Inferred from connection_id when omitted., } connection_id: { type: string, format: uuid, description: Optional tenant-owned ready X session connection; omitted means public FxTwitter API., } description: Supply url for a new capture or refresh_id to re-fetch with the tenant save record's original provider and connection. responses: "202": description: Capture accepted or existing capture reused content: application/json: schema: { $ref: "#/components/schemas/Job" } "400": { $ref: "#/components/responses/BadRequest" } "401": { $ref: "#/components/responses/Unauthorized" } "404": { $ref: "#/components/responses/NotFound" } "409": description: Idempotency conflict or storage quota exceeded content: application/json: schema: { $ref: "#/components/schemas/Error" } "422": description: Account authentication or provider unsupported content: application/json: schema: { $ref: "#/components/schemas/Error" } "429": description: Tenant capture rate exceeded; Retry-After is returned /v1/jobs/{id}: get: summary: Read capture status parameters: [{ $ref: "#/components/parameters/ID" }] responses: "200": description: Capture content: application/json: schema: { $ref: "#/components/schemas/Job" } "401": { $ref: "#/components/responses/Unauthorized" } "404": { $ref: "#/components/responses/NotFound" } /v1/collections: get: summary: List this tenant's collection, newest first description: Cookie sessions always use filtered collection pagination. Bearer requests with no filter parameters retain legacy cursor semantics. Filtered cursors are bound to the filter values and include their own sorting anchor. parameters: - { in: query, name: q, schema: { type: string, maxLength: 500 }, description: Literal case-insensitive substring in current text, summary or author name., } - { in: query, name: media_type, schema: { type: string, enum: [image, video, text] }, description: Mixed posts match image and video; avatar resources are excluded., } - { in: query, name: visibility, schema: { type: string, enum: [public, private] }, } - { in: query, name: saved_from, schema: { type: string, format: date-time }, description: Inclusive saved time., } - { in: query, name: saved_before, schema: { type: string, format: date-time }, description: Exclusive saved time., } - in: query name: cursor schema: { type: string } description: Opaque cursor returned by a previous page; pages contain at most 10 collections. responses: "200": description: Page content: application/json: schema: type: object properties: items: { type: array, items: { $ref: "#/components/schemas/Collection" }, } next_cursor: { type: string } previous_cursor: { type: string } "400": { $ref: "#/components/responses/BadRequest" } "401": { $ref: "#/components/responses/Unauthorized" } "404": { $ref: "#/components/responses/NotFound" } /v1/collections/{id}: delete: summary: Remove this tenant's collection reference and release its logical usage parameters: [{ $ref: "#/components/parameters/ID" }] responses: "204": { description: Collection reference removed; other tenants are unaffected, } "401": { $ref: "#/components/responses/Unauthorized" } "404": { $ref: "#/components/responses/NotFound" } get: summary: Read the current retained revision parameters: [{ $ref: "#/components/parameters/ID" }] responses: "200": description: Collection content: application/json: schema: { $ref: "#/components/schemas/Collection" } "401": { $ref: "#/components/responses/Unauthorized" } "404": { $ref: "#/components/responses/NotFound" } /v1/entities/{id}: get: summary: Read the latest entity version linked to your saved collections parameters: [{ $ref: "#/components/parameters/ID" }] responses: "200": description: Entity snapshot including adapter schema and resources content: application/json: schema: { $ref: "#/components/schemas/Entity" } "404": { $ref: "#/components/responses/NotFound" } /v1/collections/{id}/sources: get: summary: List up to 100 latest retained upstream responses visible to this tenant parameters: [{ $ref: "#/components/parameters/ID" }] responses: "200": description: Raw response descriptors; personal account responses are owner-only content: application/json: schema: { type: array, items: { $ref: "#/components/schemas/SourceResponse" }, } "404": { $ref: "#/components/responses/NotFound" } /v1/sources/{id}: get: summary: Download the original upstream JSON response body without reserialization parameters: [{ $ref: "#/components/parameters/ID" }] responses: "200": description: Original UTF-8 response bytes, private/no-store content: application/json: schema: {} "404": { $ref: "#/components/responses/NotFound" } /v1/assets/{id}: head: summary: Read authorized media headers without a body parameters: [{ $ref: "#/components/parameters/ID" }] responses: "200": { description: Media headers including size and Accept-Ranges } "404": { $ref: "#/components/responses/NotFound" } get: summary: Download or preview authorized saved original media parameters: - { $ref: "#/components/parameters/ID" } - { in: query, name: inline, schema: { type: string, enum: ["1"] }, description: Inline display for supported image and video MIME types., } - { in: header, name: Range, schema: { type: string }, description: Single byte range only., } responses: "200": description: Original bytes; private/no-store; attachment disposition content: image/png: { schema: { type: string, format: binary } } image/jpeg: { schema: { type: string, format: binary } } image/webp: { schema: { type: string, format: binary } } "401": { $ref: "#/components/responses/Unauthorized" } "404": { $ref: "#/components/responses/NotFound" } "206": { description: Partial media bytes with Content-Range } "416": { description: Invalid or multiple ranges } "503": { description: Object store unavailable } /v1/usage: get: summary: Shared tenant storage use across all channel identities responses: "200": description: Usage in bytes, excluding DB indexes, queue, backups and logs content: application/json: schema: type: object required: [used_bytes, reserved_bytes, limit_bytes, unlimited] properties: used_bytes: { type: integer, format: int64 } reserved_bytes: { type: integer, format: int64 } limit_bytes: { type: integer, format: int64, description: "Configured quota; not enforced when unlimited is true", } unlimited: { type: boolean } "401": { $ref: "#/components/responses/Unauthorized" }components: securitySchemes: webSession: { type: apiKey, in: cookie, name: __Host-midden, description: Cookie write requests require matching Origin. Explicit invalid Bearer credentials never fall back to a cookie., } bearerAuth: { type: http, scheme: bearer } parameters: ID: { in: path, name: id, required: true, schema: { type: string, format: uuid }, } responses: Unauthorized: description: Missing, invalid or revoked tenant token content: application/json: schema: { $ref: "#/components/schemas/Error" } NotFound: description: Resource absent or not visible to tenant content: application/json: schema: { $ref: "#/components/schemas/Error" } BadRequest: description: Invalid input content: application/json: schema: { $ref: "#/components/schemas/Error" } schemas: Error: type: object required: [error] properties: error: { type: string } Job: type: object properties: id: { type: string, format: uuid } collection_id: { type: string, format: uuid, description: Provisional while queued; read the completed job for the final shared collection ID., } state: { type: string, enum: [queued, downloading, complete, partial, failed], } error: { type: string } provider_id: { type: string } connection_id: { type: string, format: uuid } access_scope: { type: string } created_at: { type: string, format: date-time } Asset: type: object properties: purpose: { type: string, description: Adapter-defined role; empty means presentation media, } id: { type: string, format: uuid } position: { type: integer } state: { type: string, enum: [pending, ready, failed] } error: { type: string } sha256: { type: string } mime: { type: string } size: { type: integer, format: int64 } Entity: type: object properties: id: { type: string, format: uuid } version_id: { type: string, format: uuid } key: { type: string } type: { type: string, description: Adapter-defined entity type } external_id: { type: string } data: { description: Adapter-defined JSON value } schema: { type: object, description: JSON Schema snapshot used to validate this version, } resource_indices: { type: array, items: { type: integer, minimum: 0 } } assets: { type: array, items: { $ref: "#/components/schemas/Asset" } } EntityGraph: type: object properties: root: { type: string } entities: { type: array, items: { $ref: "#/components/schemas/Entity" } } relations: type: array items: type: object properties: source: { type: string } target: { type: string } type: { type: string } SourceResponse: type: object properties: id: { type: string, format: uuid } capture_id: { type: string, format: uuid } provider_id: { type: string } adapter_version: { type: string } visibility: { type: string, enum: [public, private] } content_type: { type: string } source_url: { type: string, format: uri } sha256: { type: string } size: { type: integer, format: int64 } created_at: { type: string, format: date-time } Collection: type: object properties: saved_at: { type: string, format: date-time, description: Included in filtered collection results., } id: { type: string, format: uuid } url: { type: string, format: uri } external_id: { type: string } provider_id: { type: string } access_scope: { type: string } revision_id: { type: string, format: uuid } visibility: { type: string, enum: [public, private], description: Visibility declared by the provider, } text: { type: string } summary: { type: string, description: Adapter-provided collection summary } author_name: { type: string } published_at: { type: string, format: date-time } text_kind: { type: string, enum: [provider_summary, post_text] } graph: { $ref: "#/components/schemas/EntityGraph" } text_source: { type: string, description: Source of the saved text } adapter_version: { type: string } warnings: { type: array, items: { type: string } } assets: { type: array, items: { $ref: "#/components/schemas/Asset" } } observed_at: { type: string, format: date-time } created_at: { type: string, format: date-time }