mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 04:32:42 +00:00
docs(api): publish sourceInstance on the upload and lookup routes, and the picker's review changes
This commit is contained in:
1 parent
1eac05b454
commit
6a751bc51d
3 files changed
+111
-44
No files matched your search
+80
-38
@@ -15721,21 +15721,23 @@ paths:
|
||||
|
||||
|
||||
**Importing from another system (v1.39.2).** Optional `sourceSystem` (`PAPERLESS`, `PAPRA`, `OTHER`) and
|
||||
`sourceId` (its id there, printable, up to 128 characters; needs `sourceSystem`) key the upload. A re-send with
|
||||
a known key is a duplicate: 200 with the live row (`meta.duplicate: true`), or, when the owner DELETED that
|
||||
document, 200 with `data.deleted: true` and `meta.deleted: true` and nothing stored; this holds after the 30-day
|
||||
purge too. The key may also ride the query string (`?sourceSystem=…&sourceId=…`): a key the vault already holds
|
||||
is then answered at once, the file is not stored or processed, and the request counts only toward the lookup
|
||||
allowance shared with `GET /api/documents/inbound/source` (5000 an hour per token, per person for a session; 429
|
||||
past it), not toward the hourly upload limit. A key in both places must agree (else 422). Every other upload
|
||||
counts toward the hourly upload limit, duplicates included. A key that is answered with an existing document by
|
||||
its bytes is remembered for that document, so deleting it keeps that key deleted too; one document takes at most
|
||||
20 such keys, beyond which the upload is refused 409 (`documents.inbound.sourceAliasLimit`). `OTHER` is one
|
||||
shared namespace per account: two different systems both sent as `OTHER` must not reuse each other's ids.
|
||||
`aiRead=defer` holds back automatic AI reading for this upload: the thumbnail and a local text index still run,
|
||||
the summary and lab staging do not, and the document stays out of every automatic AI path (the summary catch-up,
|
||||
the automatic index, Index all for search) until the person reads it with AI or generates its summary. Absent,
|
||||
behaviour is unchanged.
|
||||
`sourceId` (its id there, printable, up to 128 characters, never `.` or `..`; needs `sourceSystem`) key the
|
||||
upload, optionally with `sourceInstance` (v1.39.3: the address of the Paperless-ngx or Papra it came from,
|
||||
normalised to its origin; without it the key matches any instance of the system). A re-send with a known key is
|
||||
a duplicate: 200 with the live row (`meta.duplicate: true`), or, when the owner DELETED that document, 200 with
|
||||
`data.deleted: true` and `meta.deleted: true` and nothing stored; this holds after the 30-day purge too. The key
|
||||
may also ride the query string (`?sourceSystem=…&sourceId=…`): a key the vault already holds is then answered at
|
||||
once, the file is not stored or processed, and the request counts only toward the lookup allowance shared with
|
||||
`GET /api/documents/inbound/source` (5000 an hour per token, per person for a session; 429 past it), not toward
|
||||
the hourly upload limit. A key in both places must agree (else 422). Every other upload counts toward the hourly
|
||||
upload limit, duplicates included. A key that is answered with an existing document by its bytes is remembered
|
||||
for that document, so deleting it keeps that key deleted too; one document takes at most 20 such keys, beyond
|
||||
which the upload is refused 409 (`documents.inbound.sourceAliasLimit`). `OTHER` is one shared namespace per
|
||||
account: two different systems both sent as `OTHER` must not reuse each other's ids. `aiRead=defer` holds back
|
||||
automatic AI reading for this upload: the thumbnail and a local text index still run, the summary and lab
|
||||
staging do not, and the document stays out of every automatic AI path (the summary catch-up, the automatic
|
||||
index, Index all for search) until the person reads it with AI or generates its summary. Absent, behaviour is
|
||||
unchanged.
|
||||
|
||||
|
||||
**Narrow token.** Also reachable with a `documents:write` Bearer (minted at `POST /api/tokens/documents`), which
|
||||
@@ -15767,6 +15769,16 @@ paths:
|
||||
type: string
|
||||
maxLength: 128
|
||||
description: Import source key, second half. Both halves or neither; half a key is 422.
|
||||
- name: sourceInstance
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
maxLength: 512
|
||||
description: "Optional, with a key. The instance of `sourceSystem` the id belongs to, as its http(s) address; normalised
|
||||
to the origin (`scheme://host[:port]`). The same id in two instances is two documents. Optional: a key
|
||||
stored without an instance (every upload before v1.39.3) matches any instance of its system, and a key sent
|
||||
without one matches any stored instance. If also sent in the form it must agree."
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
@@ -15821,6 +15833,13 @@ paths:
|
||||
documents.
|
||||
type: string
|
||||
maxLength: 128
|
||||
sourceInstance:
|
||||
description: "Optional; requires `sourceId`. The instance of `sourceSystem` the id belongs to, as its http(s) address;
|
||||
normalised to the origin (`scheme://host[:port]`). The same id in two instances is two documents.
|
||||
Optional: a key stored without an instance (every upload before v1.39.3) matches any instance of its
|
||||
system, and a key sent without one matches any stored instance."
|
||||
type: string
|
||||
maxLength: 512
|
||||
aiRead:
|
||||
description: Optional. `defer` holds back automatic AI reading for this upload (local index and thumbnail only).
|
||||
type: string
|
||||
@@ -15896,6 +15915,16 @@ paths:
|
||||
schema:
|
||||
type: string
|
||||
maxLength: 128
|
||||
- name: sourceInstance
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
maxLength: 512
|
||||
description: "The instance of `sourceSystem` the id belongs to, as its http(s) address; normalised to the origin
|
||||
(`scheme://host[:port]`). The same id in two instances is two documents. Optional: a key stored without an
|
||||
instance (every upload before v1.39.3) matches any instance of its system, and a key sent without one
|
||||
matches any stored instance."
|
||||
responses:
|
||||
"200":
|
||||
description: The answer for this key.
|
||||
@@ -20975,7 +21004,9 @@ paths:
|
||||
at least one origin), the listed origins, and the caller's own saved connections to Paperless-ngx or Papra. A
|
||||
connection never carries its token: `hasToken` is always true for a saved one, and no route returns the token in
|
||||
whole or in part. `originAllowed` is false once the operator removed the connection's origin from the list. No
|
||||
request leaves the server. Cookie session only; not delegable."
|
||||
request leaves the server. Needs neither the Documents module nor the list: with the list unset, `available` is
|
||||
false and any connection still stored is listed (with `originAllowed: false`) so it can be removed. Cookie
|
||||
session only; not delegable."
|
||||
security: &a52
|
||||
- cookieAuth: []
|
||||
responses:
|
||||
@@ -21004,9 +21035,11 @@ paths:
|
||||
description: "Saves or replaces the caller's connection to Paperless-ngx (`paperless`: base address and API token) or
|
||||
Papra (`papra`: base address, organization id, API key with `documents:read` and `tags:read`). The base address
|
||||
may carry a path; its origin must be listed in `DOCUMENT_SOURCE_ORIGINS`. The connection is tested live before
|
||||
anything is stored. Leaving out `token` keeps the stored one (the first save must carry it). The token is stored
|
||||
encrypted (AES-256-GCM) and never returned. Ten saves and tests a minute per person. Cookie session only; not
|
||||
delegable."
|
||||
anything is stored. Leaving out `token` keeps the stored one, but only when the new address is on the same
|
||||
origin as the saved one: the first save and a move to another origin must carry it (422
|
||||
`documents.sources.tokenRequired`), so a stored token is never sent to an address it was not saved for. A Papra
|
||||
organization id is letters, digits, `_` and `-`. The token is stored encrypted (AES-256-GCM) and never returned.
|
||||
Ten saves and tests a minute per person. Cookie session only; not delegable."
|
||||
security: *a52
|
||||
parameters:
|
||||
- &a54
|
||||
@@ -21032,9 +21065,7 @@ paths:
|
||||
maxLength: 2048
|
||||
organizationId:
|
||||
type: string
|
||||
minLength: 1
|
||||
maxLength: 128
|
||||
pattern: ^[\x21-\x7e]+$
|
||||
pattern: ^[A-Za-z0-9_-]{1,128}$
|
||||
token:
|
||||
type: string
|
||||
minLength: 1
|
||||
@@ -21084,8 +21115,8 @@ paths:
|
||||
- Documents
|
||||
summary: Remove a connection to a document archive
|
||||
description: Deletes the caller's connection for this system, and its token with it. Works even after the operator
|
||||
removed the origin from the list. `disconnected` is false when there was nothing to delete. Cookie session only;
|
||||
not delegable.
|
||||
removed the origin from the list, and with the Documents module switched off. `disconnected` is false when there
|
||||
was nothing to delete. Cookie session only; not delegable.
|
||||
security: *a52
|
||||
parameters:
|
||||
- *a54
|
||||
@@ -21160,11 +21191,13 @@ paths:
|
||||
- Documents
|
||||
summary: Search a connected archive by name, tag and date
|
||||
description: "Searches the source 25 documents at a time. `q` matches the document's name (Paperless-ngx title, Papra
|
||||
name); `tag` narrows to one of the source's tags by id; `from` / `to` to a date range, inclusive (Papra's range
|
||||
is applied to each page after it arrives, so a page can hold fewer than 25). Each result carries what the vault
|
||||
already holds under that source key: `new`, `imported` with the vault document's `documentId`, or `deleted`
|
||||
(deleted in HealthLog; importing it again stores nothing). Nothing is stored. Sixty searches a minute, shared
|
||||
with the tag read. Cookie session only; not delegable."
|
||||
name); `tag` narrows to one of the source's tags by id; `from` / `to` to a date range, inclusive (Paperless-ngx
|
||||
filters on `created__gte` / `created__lte`; Papra's range is applied to each page after it arrives). When a
|
||||
filter applied after arrival empties a page, the route reads on, up to five source pages, and `page` in the
|
||||
answer is the last source page read; ask for `page + 1` next. Each result carries what the vault already holds
|
||||
under that source key: `new`, `imported` with the vault document's `documentId`, or `deleted` (deleted in
|
||||
HealthLog; importing it again stores nothing). Nothing is stored. Sixty searches a minute, shared with the tag
|
||||
read. Cookie session only; not delegable."
|
||||
security: *a52
|
||||
parameters:
|
||||
- *a54
|
||||
@@ -21218,15 +21251,19 @@ paths:
|
||||
tags:
|
||||
- Documents
|
||||
summary: Import one picked document
|
||||
description: "Fetches one document from the source and stores it in the vault through the same path as an upload, with
|
||||
`sourceSystem` / `sourceId` provenance. A source key the vault already holds is answered without a download:
|
||||
`duplicate` for a live document (same id), `deleted` for one the person deleted in HealthLog, which is never
|
||||
stored again. Bytes already in the vault under another key are `duplicate` too, and the key is remembered for
|
||||
that document. `link` files the document against the record the picker was opened from (a condition, a visit or
|
||||
a vaccination, which must be the caller's own and live; checked before anything is fetched), including a
|
||||
duplicate. `kind` sets the document type (default OTHER). Automatic AI reading follows the person's own setting.
|
||||
Counts against the person's upload allowance (60 an hour) and storage quota. 201 for a new document, 200
|
||||
otherwise. Cookie session only; not delegable."
|
||||
description: "`sourceId` must be an id the system issues (Paperless-ngx: digits; Papra: letters, digits, `_`, `-`), else
|
||||
422 before anything is fetched. Fetches one document from the source and stores it in the vault through the same
|
||||
path as an upload, with `sourceSystem` / `sourceId` / `sourceInstance` (the connection's origin) provenance; the
|
||||
same id from another instance is another document. One import per key runs at a time; a concurrent second one
|
||||
waits and then answers `duplicate`. The key check counts toward the lookup allowance, the fetch toward the
|
||||
search allowance, and only a file that arrived toward the upload allowance. A source key the vault already holds
|
||||
is answered without a download: `duplicate` for a live document (same id), `deleted` for one the person deleted
|
||||
in HealthLog, which is never stored again. Bytes already in the vault under another key are `duplicate` too, and
|
||||
the key is remembered for that document. `link` files the document against the record the picker was opened from
|
||||
(a condition, a visit or a vaccination, which must be the caller's own and live; checked before anything is
|
||||
fetched), including a duplicate. `kind` sets the document type (default OTHER). Automatic AI reading follows the
|
||||
person's own setting. Counts against the person's upload allowance (60 an hour) and storage quota. 201 for a new
|
||||
document, 200 otherwise. Cookie session only; not delegable."
|
||||
security: *a52
|
||||
parameters:
|
||||
- *a54
|
||||
@@ -35769,6 +35806,11 @@ components:
|
||||
- type: string
|
||||
maxLength: 128
|
||||
- type: "null"
|
||||
sourceInstance:
|
||||
anyOf:
|
||||
- type: string
|
||||
maxLength: 512
|
||||
- type: "null"
|
||||
aiReadDeferred:
|
||||
type: boolean
|
||||
summary:
|
||||
|
||||
@@ -117,7 +117,7 @@ export const documentSourcePaths: NonNullable<ZodOpenApiObject["paths"]> = {
|
||||
tags: ["Documents"],
|
||||
summary: "Document archives: availability and connections",
|
||||
description:
|
||||
"Whether the operator enabled the document picker (`available`, true when `DOCUMENT_SOURCE_ORIGINS` lists at least one origin), the listed origins, and the caller's own saved connections to Paperless-ngx or Papra. A connection never carries its token: `hasToken` is always true for a saved one, and no route returns the token in whole or in part. `originAllowed` is false once the operator removed the connection's origin from the list. No request leaves the server. Cookie session only; not delegable.",
|
||||
"Whether the operator enabled the document picker (`available`, true when `DOCUMENT_SOURCE_ORIGINS` lists at least one origin), the listed origins, and the caller's own saved connections to Paperless-ngx or Papra. A connection never carries its token: `hasToken` is always true for a saved one, and no route returns the token in whole or in part. `originAllowed` is false once the operator removed the connection's origin from the list. No request leaves the server. Needs neither the Documents module nor the list: with the list unset, `available` is false and any connection still stored is listed (with `originAllowed: false`) so it can be removed. Cookie session only; not delegable.",
|
||||
security: cookieOnly,
|
||||
responses: {
|
||||
"200": {
|
||||
@@ -141,7 +141,7 @@ export const documentSourcePaths: NonNullable<ZodOpenApiObject["paths"]> = {
|
||||
tags: ["Documents"],
|
||||
summary: "Save a connection to a document archive",
|
||||
description:
|
||||
"Saves or replaces the caller's connection to Paperless-ngx (`paperless`: base address and API token) or Papra (`papra`: base address, organization id, API key with `documents:read` and `tags:read`). The base address may carry a path; its origin must be listed in `DOCUMENT_SOURCE_ORIGINS`. The connection is tested live before anything is stored. Leaving out `token` keeps the stored one (the first save must carry it). The token is stored encrypted (AES-256-GCM) and never returned. Ten saves and tests a minute per person. Cookie session only; not delegable.",
|
||||
"Saves or replaces the caller's connection to Paperless-ngx (`paperless`: base address and API token) or Papra (`papra`: base address, organization id, API key with `documents:read` and `tags:read`). The base address may carry a path; its origin must be listed in `DOCUMENT_SOURCE_ORIGINS`. The connection is tested live before anything is stored. Leaving out `token` keeps the stored one, but only when the new address is on the same origin as the saved one: the first save and a move to another origin must carry it (422 `documents.sources.tokenRequired`), so a stored token is never sent to an address it was not saved for. A Papra organization id is letters, digits, `_` and `-`. The token is stored encrypted (AES-256-GCM) and never returned. Ten saves and tests a minute per person. Cookie session only; not delegable.",
|
||||
security: cookieOnly,
|
||||
parameters: [systemParameter],
|
||||
requestBody: {
|
||||
@@ -176,7 +176,7 @@ export const documentSourcePaths: NonNullable<ZodOpenApiObject["paths"]> = {
|
||||
tags: ["Documents"],
|
||||
summary: "Remove a connection to a document archive",
|
||||
description:
|
||||
"Deletes the caller's connection for this system, and its token with it. Works even after the operator removed the origin from the list. `disconnected` is false when there was nothing to delete. Cookie session only; not delegable.",
|
||||
"Deletes the caller's connection for this system, and its token with it. Works even after the operator removed the origin from the list, and with the Documents module switched off. `disconnected` is false when there was nothing to delete. Cookie session only; not delegable.",
|
||||
security: cookieOnly,
|
||||
parameters: [systemParameter],
|
||||
responses: {
|
||||
@@ -269,7 +269,7 @@ export const documentSourcePaths: NonNullable<ZodOpenApiObject["paths"]> = {
|
||||
tags: ["Documents"],
|
||||
summary: "Search a connected archive by name, tag and date",
|
||||
description:
|
||||
"Searches the source 25 documents at a time. `q` matches the document's name (Paperless-ngx title, Papra name); `tag` narrows to one of the source's tags by id; `from` / `to` to a date range, inclusive (Papra's range is applied to each page after it arrives, so a page can hold fewer than 25). Each result carries what the vault already holds under that source key: `new`, `imported` with the vault document's `documentId`, or `deleted` (deleted in HealthLog; importing it again stores nothing). Nothing is stored. Sixty searches a minute, shared with the tag read. Cookie session only; not delegable.",
|
||||
"Searches the source 25 documents at a time. `q` matches the document's name (Paperless-ngx title, Papra name); `tag` narrows to one of the source's tags by id; `from` / `to` to a date range, inclusive (Paperless-ngx filters on `created__gte` / `created__lte`; Papra's range is applied to each page after it arrives). When a filter applied after arrival empties a page, the route reads on, up to five source pages, and `page` in the answer is the last source page read; ask for `page + 1` next. Each result carries what the vault already holds under that source key: `new`, `imported` with the vault document's `documentId`, or `deleted` (deleted in HealthLog; importing it again stores nothing). Nothing is stored. Sixty searches a minute, shared with the tag read. Cookie session only; not delegable.",
|
||||
security: cookieOnly,
|
||||
parameters: [
|
||||
systemParameter,
|
||||
@@ -335,7 +335,7 @@ export const documentSourcePaths: NonNullable<ZodOpenApiObject["paths"]> = {
|
||||
tags: ["Documents"],
|
||||
summary: "Import one picked document",
|
||||
description:
|
||||
"Fetches one document from the source and stores it in the vault through the same path as an upload, with `sourceSystem` / `sourceId` provenance. A source key the vault already holds is answered without a download: `duplicate` for a live document (same id), `deleted` for one the person deleted in HealthLog, which is never stored again. Bytes already in the vault under another key are `duplicate` too, and the key is remembered for that document. `link` files the document against the record the picker was opened from (a condition, a visit or a vaccination, which must be the caller's own and live; checked before anything is fetched), including a duplicate. `kind` sets the document type (default OTHER). Automatic AI reading follows the person's own setting. Counts against the person's upload allowance (60 an hour) and storage quota. 201 for a new document, 200 otherwise. Cookie session only; not delegable.",
|
||||
"`sourceId` must be an id the system issues (Paperless-ngx: digits; Papra: letters, digits, `_`, `-`), else 422 before anything is fetched. Fetches one document from the source and stores it in the vault through the same path as an upload, with `sourceSystem` / `sourceId` / `sourceInstance` (the connection's origin) provenance; the same id from another instance is another document. One import per key runs at a time; a concurrent second one waits and then answers `duplicate`. The key check counts toward the lookup allowance, the fetch toward the search allowance, and only a file that arrived toward the upload allowance. A source key the vault already holds is answered without a download: `duplicate` for a live document (same id), `deleted` for one the person deleted in HealthLog, which is never stored again. Bytes already in the vault under another key are `duplicate` too, and the key is remembered for that document. `link` files the document against the record the picker was opened from (a condition, a visit or a vaccination, which must be the caller's own and live; checked before anything is fetched), including a duplicate. `kind` sets the document type (default OTHER). Automatic AI reading follows the person's own setting. Counts against the person's upload allowance (60 an hour) and storage quota. 201 for a new document, 200 otherwise. Cookie session only; not delegable.",
|
||||
security: cookieOnly,
|
||||
parameters: [systemParameter],
|
||||
requestBody: {
|
||||
|
||||
@@ -24,6 +24,7 @@ import {
|
||||
inboundConfirmSchema,
|
||||
inboundFactEditSchema,
|
||||
DOCUMENT_SOURCE_ID_MAX,
|
||||
DOCUMENT_SOURCE_INSTANCE_MAX,
|
||||
DOCUMENT_SOURCE_SYSTEMS,
|
||||
DOCUMENT_SUMMARY_STATES,
|
||||
INBOUND_DOCUMENT_KINDS,
|
||||
@@ -417,12 +418,20 @@ export const inboundDocumentPaths: NonNullable<ZodOpenApiObject["paths"]> = {
|
||||
description:
|
||||
"Import source key, second half. Both halves or neither; half a key is 422.",
|
||||
},
|
||||
{
|
||||
name: "sourceInstance",
|
||||
in: "query",
|
||||
required: false,
|
||||
schema: { type: "string", maxLength: DOCUMENT_SOURCE_INSTANCE_MAX },
|
||||
description:
|
||||
"Optional, with a key. The instance of `sourceSystem` the id belongs to, as its http(s) address; normalised to the origin (`scheme://host[:port]`). The same id in two instances is two documents. Optional: a key stored without an instance (every upload before v1.39.3) matches any instance of its system, and a key sent without one matches any stored instance. If also sent in the form it must agree.",
|
||||
},
|
||||
],
|
||||
tags: ["Documents"],
|
||||
summary: "Store a document (no extraction)",
|
||||
description:
|
||||
'STORE-ONLY upload. Stores the raw document ENCRYPTED at rest with `status: STORED` and runs NO extraction — provider-free, no AI consent / budget / egress. A file is always filable, even with no document-scan provider configured. `multipart/form-data`: a `file` plus optional `title`, `kind`, `documentDate` (YYYY-MM-DD), and repeated `episodeIds` form fields (pre-link to the caller\'s illness/condition episodes). Accepted types (magic-byte sniffed, never the wire Content-Type): PDF/JPEG/PNG/WebP/GIF render inline; Office (docx/xlsx/pptx/doc/xls/ppt), text/CSV/Markdown/RTF, TIFF, HEIC/HEIF, XML/JSON are stored verbatim and served download-only. HEIC is stored as-is but attachment-only — prefer transcoding to JPEG client-side for inline preview parity. Error contract: `413` with `meta.reason = "fileTooLarge"` (+ `maxFileBytes`) or `"quotaExceeded"` (+ `quotaBytes`, `usedBytes`); `415` with `meta.reason = "unsupportedType"`. A same-user duplicate (same bytes) returns 200 + `meta.duplicate: true` with the existing row — not an error. `Idempotency-Key` honoured. Read `GET /api/documents/inbound/usage` for the effective limits before offering an upload. AI extraction is a separate opt-in action — see `POST /api/documents/inbound/{id}/extract`.\n\n' +
|
||||
"**Importing from another system (v1.39.2).** Optional `sourceSystem` (`PAPERLESS`, `PAPRA`, `OTHER`) and `sourceId` (its id there, printable, up to 128 characters; needs `sourceSystem`) key the upload. A re-send with a known key is a duplicate: 200 with the live row (`meta.duplicate: true`), or, when the owner DELETED that document, 200 with `data.deleted: true` and `meta.deleted: true` and nothing stored; this holds after the 30-day purge too. The key may also ride the query string (`?sourceSystem=…&sourceId=…`): a key the vault already holds is then answered at once, the file is not stored or processed, and the request counts only toward the lookup allowance shared with `GET /api/documents/inbound/source` (5000 an hour per token, per person for a session; 429 past it), not toward the hourly upload limit. A key in both places must agree (else 422). Every other upload counts toward the hourly upload limit, duplicates included. A key that is answered with an existing document by its bytes is remembered for that document, so deleting it keeps that key deleted too; one document takes at most 20 such keys, beyond which the upload is refused 409 (`documents.inbound.sourceAliasLimit`). `OTHER` is one shared namespace per account: two different systems both sent as `OTHER` must not reuse each other\'s ids. `aiRead=defer` holds back automatic AI reading for this upload: the thumbnail and a local text index still run, the summary and lab staging do not, and the document stays out of every automatic AI path (the summary catch-up, the automatic index, Index all for search) until the person reads it with AI or generates its summary. Absent, behaviour is unchanged.\n\n" +
|
||||
"**Importing from another system (v1.39.2).** Optional `sourceSystem` (`PAPERLESS`, `PAPRA`, `OTHER`) and `sourceId` (its id there, printable, up to 128 characters, never `.` or `..`; needs `sourceSystem`) key the upload, optionally with `sourceInstance` (v1.39.3: the address of the Paperless-ngx or Papra it came from, normalised to its origin; without it the key matches any instance of the system). A re-send with a known key is a duplicate: 200 with the live row (`meta.duplicate: true`), or, when the owner DELETED that document, 200 with `data.deleted: true` and `meta.deleted: true` and nothing stored; this holds after the 30-day purge too. The key may also ride the query string (`?sourceSystem=…&sourceId=…`): a key the vault already holds is then answered at once, the file is not stored or processed, and the request counts only toward the lookup allowance shared with `GET /api/documents/inbound/source` (5000 an hour per token, per person for a session; 429 past it), not toward the hourly upload limit. A key in both places must agree (else 422). Every other upload counts toward the hourly upload limit, duplicates included. A key that is answered with an existing document by its bytes is remembered for that document, so deleting it keeps that key deleted too; one document takes at most 20 such keys, beyond which the upload is refused 409 (`documents.inbound.sourceAliasLimit`). `OTHER` is one shared namespace per account: two different systems both sent as `OTHER` must not reuse each other\'s ids. `aiRead=defer` holds back automatic AI reading for this upload: the thumbnail and a local text index still run, the summary and lab staging do not, and the document stays out of every automatic AI path (the summary catch-up, the automatic index, Index all for search) until the person reads it with AI or generates its summary. Absent, behaviour is unchanged.\n\n" +
|
||||
"**Narrow token.** Also reachable with a `documents:write` Bearer (minted at `POST /api/tokens/documents`), which reaches only this route and the source-key lookup `GET /api/documents/inbound/source`. Such a caller draws on a bucket of its own, keyed on the token (default 120 an hour, `DOCUMENT_UPLOAD_LIMIT_PER_HOUR`, clamped 1-1000; the 429 carries `Retry-After` and `X-RateLimit-*`), and gets a `DocumentUploadReceipt` instead of the stored row; its 413 `quotaExceeded` carries no `quotaBytes` / `usedBytes`. The response is an untagged union (row or receipt) on purpose: a discriminator would need a new field on the row every existing client decodes. A cookie or wildcard caller keeps the 60-an-hour per-user bucket and the full row. With the vault module off the answer is 403 `module.disabled` for every caller.",
|
||||
requestBody: {
|
||||
required: true,
|
||||
@@ -461,6 +470,14 @@ export const inboundDocumentPaths: NonNullable<ZodOpenApiObject["paths"]> = {
|
||||
description:
|
||||
"Optional. The document's id in `sourceSystem`; requires it. Unique per account across live and deleted documents.",
|
||||
}),
|
||||
sourceInstance: z
|
||||
.string()
|
||||
.max(DOCUMENT_SOURCE_INSTANCE_MAX)
|
||||
.optional()
|
||||
.meta({
|
||||
description:
|
||||
"Optional; requires `sourceId`. The instance of `sourceSystem` the id belongs to, as its http(s) address; normalised to the origin (`scheme://host[:port]`). The same id in two instances is two documents. Optional: a key stored without an instance (every upload before v1.39.3) matches any instance of its system, and a key sent without one matches any stored instance.",
|
||||
}),
|
||||
aiRead: z.enum(["defer"]).optional().meta({
|
||||
description:
|
||||
"Optional. `defer` holds back automatic AI reading for this upload (local index and thumbnail only).",
|
||||
@@ -527,6 +544,14 @@ export const inboundDocumentPaths: NonNullable<ZodOpenApiObject["paths"]> = {
|
||||
required: true,
|
||||
schema: { type: "string", maxLength: DOCUMENT_SOURCE_ID_MAX },
|
||||
},
|
||||
{
|
||||
name: "sourceInstance",
|
||||
in: "query",
|
||||
required: false,
|
||||
schema: { type: "string", maxLength: DOCUMENT_SOURCE_INSTANCE_MAX },
|
||||
description:
|
||||
"The instance of `sourceSystem` the id belongs to, as its http(s) address; normalised to the origin (`scheme://host[:port]`). The same id in two instances is two documents. Optional: a key stored without an instance (every upload before v1.39.3) matches any instance of its system, and a key sent without one matches any stored instance.",
|
||||
},
|
||||
],
|
||||
responses: {
|
||||
"200": {
|
||||
|
||||
Reference in new issue
Block a user