{"openapi":"3.1.0","info":{"title":"Watchdog API","version":"0.0.0","description":"Watchdog public API. Server-to-server document upload and related operations.\n\n## Authentication\n\nAll `/v1/*` endpoints require a bearer token in the `Authorization` header (e.g. `Authorization: Bearer wdg_<your-token>`).\n\n**Generate a token:** sign in at [app.watchdog.no](https://app.watchdog.no), open **Settings → API keys**, and click **Create API key** (admins only). The plaintext token is shown **once** at creation and cannot be recovered — copy it into a secrets manager immediately. If lost, revoke and replace.\n\nTokens carry one or more scopes: `invoices:write` for uploads and `invoices:read` for polling. New integration keys receive both automatically. The required scope per endpoint is listed under \"Authorizations\" below."},"servers":[{"url":"https://api.watchdog.no","description":"Production"}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","description":"API key from Settings → API Keys. Plaintext is shown once at creation and cannot be recovered. Header: `Authorization: Bearer wdg_<token>`."}},"schemas":{"Health":{"type":"object","properties":{"status":{"type":"string","enum":["ok"]},"commit":{"type":"string"}},"required":["status","commit"]},"UploadInvoiceResponse":{"type":"object","properties":{"invoice_id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["queued"]},"documents":{"type":"object","properties":{"primary":{"$ref":"#/components/schemas/UploadInvoiceDocumentRef"},"attachments":{"type":"array","items":{"$ref":"#/components/schemas/UploadInvoiceDocumentRef"}}},"required":["primary","attachments"]},"created_at":{"type":"string","format":"date-time"}},"required":["invoice_id","status","documents","created_at"]},"UploadInvoiceDocumentRef":{"type":"object","properties":{"document_id":{"type":"string","format":"uuid"},"file_name":{"type":"string"},"mime_type":{"type":"string","enum":["application/pdf","application/xml","text/xml"]}},"required":["document_id","file_name","mime_type"]},"ErrorBody_invalid_request":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["invalid_request"]},"message":{"type":"string"},"description":{"type":"string"},"request_id":{"type":"string"}},"required":["code","message","request_id"]}},"required":["error"]},"ErrorBody_too_many_attachments":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["too_many_attachments"]},"message":{"type":"string"},"description":{"type":"string"},"request_id":{"type":"string"}},"required":["code","message","request_id"]}},"required":["error"]},"ErrorBody_per_file_validation":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["invalid_xml_invoice","unnamed_file","unsupported_media_type","file_too_small","payload_too_large"]},"message":{"type":"string"},"description":{"type":"string"},"request_id":{"type":"string"},"field":{"type":"string"},"filename":{"type":"string"}},"required":["code","message","request_id","field","filename"]}},"required":["error"]},"ErrorBody_invalid_token":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["invalid_token"]},"message":{"type":"string"},"description":{"type":"string"},"request_id":{"type":"string"}},"required":["code","message","request_id"]}},"required":["error"]},"ErrorBody_token_disabled":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["token_disabled"]},"message":{"type":"string"},"description":{"type":"string"},"request_id":{"type":"string"}},"required":["code","message","request_id"]}},"required":["error"]},"ErrorBody_insufficient_scope":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["insufficient_scope"]},"message":{"type":"string"},"description":{"type":"string"},"request_id":{"type":"string"}},"required":["code","message","request_id"]}},"required":["error"]},"ErrorBody_invoice_processing_capacity_exhausted":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["invoice_processing_capacity_exhausted"]},"message":{"type":"string"},"description":{"type":"string"},"request_id":{"type":"string"}},"required":["code","message","request_id"]}},"required":["error"]},"ErrorBody_duplicate_invoice":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["duplicate_invoice"]},"message":{"type":"string"},"description":{"type":"string"},"request_id":{"type":"string"},"existing_invoice_id":{"type":"string","format":"uuid"}},"required":["code","message","request_id","existing_invoice_id"]}},"required":["error"]},"ErrorBody_primary_md5_locked_by_deleted_invoice":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["primary_md5_locked_by_deleted_invoice"]},"message":{"type":"string"},"description":{"type":"string"},"request_id":{"type":"string"},"existing_invoice_id":{"type":"string","format":"uuid"}},"required":["code","message","request_id","existing_invoice_id"]}},"required":["error"]},"ErrorBody_length_required":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["length_required"]},"message":{"type":"string"},"description":{"type":"string"},"request_id":{"type":"string"}},"required":["code","message","request_id"]}},"required":["error"]},"ErrorBody_payload_too_large":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["payload_too_large"]},"message":{"type":"string"},"description":{"type":"string"},"request_id":{"type":"string"}},"required":["code","message","request_id"]}},"required":["error"]},"ErrorBody_unsupported_media_type":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["unsupported_media_type"]},"message":{"type":"string"},"description":{"type":"string"},"request_id":{"type":"string"}},"required":["code","message","request_id"]}},"required":["error"]},"ErrorBody_rate_limit_exceeded":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["rate_limit_exceeded"]},"message":{"type":"string"},"description":{"type":"string"},"request_id":{"type":"string"}},"required":["code","message","request_id"]}},"required":["error"]},"ErrorBody_internal_error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["internal_error"]},"message":{"type":"string"},"description":{"type":"string"},"request_id":{"type":"string"}},"required":["code","message","request_id"]}},"required":["error"]},"ErrorBody_service_unavailable":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["service_unavailable"]},"message":{"type":"string"},"description":{"type":"string"},"request_id":{"type":"string"}},"required":["code","message","request_id"]}},"required":["error"]},"UploadInvoiceRequest":{"type":"object","required":["primary"],"properties":{"primary":{"type":"string","format":"binary","description":"Primary invoice document. Max 50 MB."},"attachments":{"type":"array","items":{"type":"string","format":"binary"},"description":"Optional supporting documents (0–9). Max 25 MB each. Combined body (primary + attachments) max 100 MB."}}},"InvoiceListResponse":{"type":"object","properties":{"invoices":{"type":"array","items":{"$ref":"#/components/schemas/InvoiceStatusResponse"}},"next_cursor":{"type":["string","null"],"description":"Opaque cursor for the next page, or `null` when no more invoices remain."}},"required":["invoices","next_cursor"]},"InvoiceStatusResponse":{"type":"object","properties":{"invoice_id":{"type":"string","format":"uuid","description":"Watchdog invoice identifier returned by the upload endpoint.","example":"7ad2c50d-2cc0-49a0-9a9c-6fa817c1fbcb"},"invoice_number":{"type":["string","null"],"description":"Invoice number extracted from the document. May be `null` before extraction or when no number can be identified; it is not a unique identifier.","example":"100234"},"processing":{"anyOf":[{"type":"object","properties":{"status":{"type":"string","enum":["pending","processing"]},"classification":{"type":"null"},"failure":{"type":"null"}},"required":["status","classification","failure"]},{"type":"object","properties":{"status":{"type":"string","enum":["completed"]},"classification":{"type":"string","enum":["invoice","credit_note","self_billed_invoice","not_invoice"]},"failure":{"type":"null"}},"required":["status","classification","failure"]},{"type":"object","properties":{"status":{"type":"string","enum":["failed"]},"classification":{"type":"null"},"failure":{"type":"object","properties":{"code":{"type":"string","enum":["invoice_processing_failed"]},"message":{"type":"string","enum":["Watchdog could not process this document."]}},"required":["code","message"]}},"required":["status","classification","failure"]}]},"alerts":{"anyOf":[{"type":"object","properties":{"processing":{"type":"object","properties":{"status":{"type":"string","enum":["pending","processing"]},"skip_reason":{"type":"null"},"failure":{"type":"null"}},"required":["status","skip_reason","failure"]},"result":{"type":"null"},"count":{"type":"null"},"resolution":{"type":"null"}},"required":["processing","result","count","resolution"]},{"type":"object","properties":{"processing":{"type":"object","properties":{"status":{"type":"string","enum":["pending","processing"]},"skip_reason":{"type":"null"},"failure":{"type":"null"}},"required":["status","skip_reason","failure"]},"result":{"type":"string","enum":["alerts_found"]},"count":{"type":"integer","exclusiveMinimum":0},"resolution":{"anyOf":[{"type":"object","properties":{"status":{"type":"string","enum":["open"]},"method":{"type":"null"}},"required":["status","method"]},{"type":"object","properties":{"status":{"type":"string","enum":["resolved"]},"method":{"type":"string","enum":["credit_note"]}},"required":["status","method"]},{"type":"object","properties":{"status":{"type":"string","enum":["resolved"]},"method":{"type":"string","enum":["manual_review"]}},"required":["status","method"]}]}},"required":["processing","result","count","resolution"]},{"type":"object","properties":{"processing":{"type":"object","properties":{"status":{"type":"string","enum":["completed"]},"skip_reason":{"type":"null"},"failure":{"type":"null"}},"required":["status","skip_reason","failure"]},"result":{"type":"string","enum":["no_alerts_found"]},"count":{"type":"number","enum":[0]},"resolution":{"type":"null"}},"required":["processing","result","count","resolution"]},{"type":"object","properties":{"processing":{"type":"object","properties":{"status":{"type":"string","enum":["completed"]},"skip_reason":{"type":"null"},"failure":{"type":"null"}},"required":["status","skip_reason","failure"]},"result":{"type":"string","enum":["alerts_found"]},"count":{"type":"integer","exclusiveMinimum":0},"resolution":{"anyOf":[{"type":"object","properties":{"status":{"type":"string","enum":["open"]},"method":{"type":"null"}},"required":["status","method"]},{"type":"object","properties":{"status":{"type":"string","enum":["resolved"]},"method":{"type":"string","enum":["credit_note"]}},"required":["status","method"]},{"type":"object","properties":{"status":{"type":"string","enum":["resolved"]},"method":{"type":"string","enum":["manual_review"]}},"required":["status","method"]}]}},"required":["processing","result","count","resolution"]},{"type":"object","properties":{"processing":{"type":"object","properties":{"status":{"type":"string","enum":["failed"]},"skip_reason":{"type":"null"},"failure":{"type":"object","properties":{"code":{"type":"string","enum":["some_alert_checks_failed"]},"message":{"type":"string","enum":["Some agreement checks could not be completed."]}},"required":["code","message"]}},"required":["status","skip_reason","failure"]},"result":{"type":"null"},"count":{"type":"null"},"resolution":{"type":"null"}},"required":["processing","result","count","resolution"]},{"type":"object","properties":{"processing":{"type":"object","properties":{"status":{"type":"string","enum":["failed"]},"skip_reason":{"type":"null"},"failure":{"type":"object","properties":{"code":{"type":"string","enum":["some_alert_checks_failed"]},"message":{"type":"string","enum":["Some agreement checks could not be completed."]}},"required":["code","message"]}},"required":["status","skip_reason","failure"]},"result":{"type":"string","enum":["alerts_found"]},"count":{"type":"integer","exclusiveMinimum":0},"resolution":{"anyOf":[{"type":"object","properties":{"status":{"type":"string","enum":["open"]},"method":{"type":"null"}},"required":["status","method"]},{"type":"object","properties":{"status":{"type":"string","enum":["resolved"]},"method":{"type":"string","enum":["credit_note"]}},"required":["status","method"]},{"type":"object","properties":{"status":{"type":"string","enum":["resolved"]},"method":{"type":"string","enum":["manual_review"]}},"required":["status","method"]}]}},"required":["processing","result","count","resolution"]},{"type":"object","properties":{"processing":{"type":"object","properties":{"status":{"type":"string","enum":["skipped"]},"skip_reason":{"type":"string","enum":["not_an_invoice","invoice_processing_failed","credit_note","no_applicable_agreements","credit_note_matched"]},"failure":{"type":"null"}},"required":["status","skip_reason","failure"]},"result":{"type":"null"},"count":{"type":"null"},"resolution":{"type":"null"}},"required":["processing","result","count","resolution"]}],"description":"Aggregate alert-assessment summary across all applicable agreements. `count` preserves detected, non-superseded alerts even after review; `resolution` indicates whether they remain blocking. Individual alerts and agreement-level results are not exposed; use `invoice_url` to inspect them in Watchdog."},"invoice_url":{"type":"string","format":"uri","description":"Absolute URL for reviewing the invoice and its alerts in Watchdog.","example":"https://app.watchdog.no/org_3AFsEYath1408oAK0EkJikS8qp1/invoices/7ad2c50d-2cc0-49a0-9a9c-6fa817c1fbcb"},"created_at":{"type":"string","format":"date-time","description":"When the invoice resource was created.","example":"2026-08-12T07:44:20.000Z"}},"required":["invoice_id","invoice_number","processing","alerts","invoice_url","created_at"]},"ErrorBody_validation_error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["validation_error"]},"message":{"type":"string"},"description":{"type":"string"},"request_id":{"type":"string"}},"required":["code","message","request_id"]}},"required":["error"]},"ErrorBody_not_found":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["not_found"]},"message":{"type":"string"},"description":{"type":"string"},"request_id":{"type":"string"}},"required":["code","message","request_id"]}},"required":["error"]}},"parameters":{}},"paths":{"/health":{"get":{"tags":["operations"],"summary":"Health check","description":"Returns 200 when the API process is up. No dependency checks.","responses":{"200":{"description":"Service is up","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Health"}}}}}}},"/v1/invoices/upload":{"post":{"tags":["invoices"],"summary":"Upload an invoice","description":"Submit a `primary` invoice document and optional `attachments` as `multipart/form-data`.\n\nFiles (primary and attachments) must be PDF, **Peppol BIS Billing 3.0** (UBL 2.1 — root `Invoice` or `CreditNote`), or **Finvoice 3.0** (root `Finvoice`). XML is matched on the root element name only; documents are not schema-validated. If any file fails validation, no invoice is created.\n\nDeduplicated by primary-document MD5 within the organization. A replay returns 409 `duplicate_invoice`, or `primary_md5_locked_by_deleted_invoice` if the original was soft-deleted (an admin must hard-delete to free the MD5).\n\nNew invoices also require current processing capacity. A 403 `invoice_processing_capacity_exhausted` means no invoice or documents were retained; retry only after organization capacity may have changed. A temporary admission-coordination failure returns 503 `service_unavailable` with `Retry-After: 1`.\n\nThe 201 includes a `Location` header at `/v1/invoices/{invoice_id}`. Poll that resource with an `invoices:read` token and respect its `Retry-After` header while either processing status is `pending` or `processing`.","security":[{"BearerAuth":["invoices:write"]}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/UploadInvoiceRequest"}}}},"responses":{"201":{"description":"Invoice created and queued for processing.","headers":{"Location":{"schema":{"type":"string"},"description":"URL of the pollable invoice resource (`/v1/invoices/{invoice_id}`)."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadInvoiceResponse"}}}},"400":{"description":"Invalid multipart body, or a per-file validation failed. Per-file errors include `field` and `filename` so the client can pinpoint the offending file.","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ErrorBody_invalid_request"},{"$ref":"#/components/schemas/ErrorBody_too_many_attachments"},{"$ref":"#/components/schemas/ErrorBody_per_file_validation"}]}}}},"401":{"description":"Authentication failed — missing, malformed, unknown, or revoked token. See `WWW-Authenticate` header per RFC 6750.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody_invalid_token"}}}},"403":{"description":"The token is disabled or lacks the required scope, or current organization capacity forbids accepting another invoice. `invoice_processing_capacity_exhausted` retains no invoice or documents; retry only after organization capacity may have changed.","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ErrorBody_token_disabled"},{"$ref":"#/components/schemas/ErrorBody_insufficient_scope"},{"$ref":"#/components/schemas/ErrorBody_invoice_processing_capacity_exhausted"}]}}}},"409":{"description":"The primary document duplicates an existing or soft-deleted invoice. Both codes include `existing_invoice_id`.","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ErrorBody_duplicate_invoice"},{"$ref":"#/components/schemas/ErrorBody_primary_md5_locked_by_deleted_invoice"}]}}}},"411":{"description":"`Content-Length` header is required for this endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody_length_required"}}}},"413":{"description":"Request body exceeds the per-file or combined-body cap.","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ErrorBody_payload_too_large"},{"$ref":"#/components/schemas/ErrorBody_per_file_validation"}]}}}},"415":{"description":"Unsupported MIME type, or the primary file failed magic-byte validation.","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ErrorBody_unsupported_media_type"},{"$ref":"#/components/schemas/ErrorBody_per_file_validation"}]}}}},"429":{"description":"Rate limit exceeded. Pre-auth IP cap is 300 req/min; per-token cap is 120 req/min. Response headers indicate when the caller may retry.","headers":{"Retry-After":{"description":"Seconds until the caller may retry. Only present on 429 responses.","schema":{"type":"string","example":"34"}},"X-RateLimit-Limit":{"description":"Maximum requests allowed in the current window.","schema":{"type":"string","example":"300"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current window.","schema":{"type":"string","example":"0"}},"X-RateLimit-Reset":{"description":"Unix timestamp in seconds when the current window resets. Divide by 1000 if you have a millisecond-precision clock.","schema":{"type":"string","example":"1713793234"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody_rate_limit_exceeded"}}}},"500":{"description":"Internal error processing the upload.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody_internal_error"}}}},"503":{"description":"Invoice admission coordination is temporarily unavailable. The same request may be retried shortly.","headers":{"Retry-After":{"schema":{"type":"string","example":"1"},"description":"Retry delay in seconds for this temporary coordination failure."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody_service_unavailable"}}}}}}},"/v1/invoices":{"get":{"tags":["invoices"],"summary":"List invoices","description":"Lists every non-deleted invoice belonging to the token organization, regardless of import source.\n\nResults default to newest first. Use `sort` and `direction` to choose an allowlisted order. Pass `next_cursor` as `cursor` to continue; omitted sorting parameters are inherited from the cursor, while contradictory parameters return `400`.\n\nCursors are opaque and remain usable if the invoice at the preceding page boundary is deleted.\n\nEach item is the same invoice resource returned by `GET /v1/invoices/{invoice_id}`. Open `invoice_url` in Watchdog for details and alert review.","security":[{"BearerAuth":["invoices:read"]}],"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":100,"default":50,"description":"Maximum invoices to return. Defaults to 50 and cannot exceed 100.","example":50},"required":false,"description":"Maximum invoices to return. Defaults to 50 and cannot exceed 100.","name":"limit","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":512,"description":"Opaque continuation cursor from the preceding response. It retains the selected sort and direction.","example":"eyJ2IjoxLCJyZXNvdXJjZSI6Imludm9pY2VzIiwic29ydCI6ImNyZWF0ZWRfYXQiLCJkaXJlY3Rpb24iOiJkZXNjIiwic29ydF92YWx1ZSI6IjE3ODY0NjM5NjAwNjEwMDAiLCJpZCI6IjdhZDJjNTBkLTJjYzAtNDlhMC05YTljLTZmYTgxN2MxZmJjYiJ9"},"required":false,"description":"Opaque continuation cursor from the preceding response. It retains the selected sort and direction.","name":"cursor","in":"query"},{"schema":{"type":"string","enum":["created_at"],"default":"created_at","description":"Field used to order invoices. Defaults to `created_at` for an initial request and is inherited from the cursor on continuation.","example":"created_at"},"required":false,"description":"Field used to order invoices. Defaults to `created_at` for an initial request and is inherited from the cursor on continuation.","name":"sort","in":"query"},{"schema":{"type":"string","enum":["asc","desc"],"default":"desc","description":"Sort direction. Defaults to `desc` for an initial request and is inherited from the cursor on continuation.","example":"desc"},"required":false,"description":"Sort direction. Defaults to `desc` for an initial request and is inherited from the cursor on continuation.","name":"direction","in":"query"}],"responses":{"200":{"description":"A page of invoices ordered by the selected field and invoice ID.","headers":{"Cache-Control":{"schema":{"type":"string","example":"no-store"},"description":"Prevents changing invoice states from being cached."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvoiceListResponse"},"example":{"invoices":[{"invoice_id":"7ad2c50d-2cc0-49a0-9a9c-6fa817c1fbcb","invoice_number":"100234","processing":{"status":"completed","classification":"invoice","failure":null},"alerts":{"processing":{"status":"completed","skip_reason":null,"failure":null},"result":"no_alerts_found","count":0,"resolution":null},"invoice_url":"https://app.watchdog.no/org_3AFsEYath1408oAK0EkJikS8qp1/invoices/7ad2c50d-2cc0-49a0-9a9c-6fa817c1fbcb","created_at":"2026-08-12T07:44:20.000Z"}],"next_cursor":null}}}},"400":{"description":"The limit, sort, direction, or cursor is invalid.","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ErrorBody_validation_error"},{"$ref":"#/components/schemas/ErrorBody_invalid_request"}]}}}},"401":{"description":"Authentication failed — missing, malformed, unknown, or revoked token. See `WWW-Authenticate` header per RFC 6750.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody_invalid_token"}}}},"403":{"description":"Token is disabled (operator-controlled kill switch) or lacks the required scope.","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ErrorBody_token_disabled"},{"$ref":"#/components/schemas/ErrorBody_insufficient_scope"}]}}}},"429":{"description":"Rate limit exceeded. Pre-auth IP cap is 300 req/min; per-token cap is 120 req/min. Response headers indicate when the caller may retry.","headers":{"Retry-After":{"description":"Seconds until the caller may retry. Only present on 429 responses.","schema":{"type":"string","example":"34"}},"X-RateLimit-Limit":{"description":"Maximum requests allowed in the current window.","schema":{"type":"string","example":"300"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current window.","schema":{"type":"string","example":"0"}},"X-RateLimit-Reset":{"description":"Unix timestamp in seconds when the current window resets. Divide by 1000 if you have a millisecond-precision clock.","schema":{"type":"string","example":"1713793234"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody_rate_limit_exceeded"}}}},"500":{"description":"Internal error listing invoices.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody_internal_error"}}}}}}},"/v1/invoices/{invoice_id}":{"get":{"tags":["invoices"],"summary":"Get invoice","description":"Poll the invoice resource returned in the upload `Location` header or referenced by `existing_invoice_id` in a duplicate response.\n\nThe `processing` and `alerts.processing` objects have independent lifecycles. Continue polling while either status is `pending` or `processing`, and respect `Retry-After` before polling again.\n\n`alerts` is an aggregate across applicable agreements: active agreements with a confirmed or auto-confirmed invoice match. An applicable agreement that cannot be checked makes the aggregate fail; only an invoice without such agreements uses `no_applicable_agreements`.\n\n`count` contains detected, non-superseded alerts and may increase while assessment is active. Dismissed alerts remain in the detected count, while `resolution` indicates whether the findings remain blocking: `manual_review` means every current alert was dismissed, and `credit_note` means the invoice has a matched credit note. A null count during active processing does not mean that no alerts were found. Individual alerts and agreement-level results remain available through `invoice_url`.\n\n`alerts.result` and `alerts.resolution` must be interpreted together with `alerts.processing.status`. Neither is by itself an approval signal while alert processing is `pending`, `processing`, or `failed`: active assessment may find more alerts, and failed assessment is incomplete. `completed` is conclusive for the current snapshot; `skipped` means assessment did not run and is explained by `skip_reason`.\n\nThis response is a current snapshot, not an immutable assessment event. A terminal response may change after agreement edits, rechecks, alert review, replacements, or credit-note matching. Consumers that need later changes must fetch the resource again on their own cadence.\n\n`invoice_id` is the stable API identifier. `invoice_number` is extracted metadata and must not be treated as unique.","security":[{"BearerAuth":["invoices:read"]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Invoice identifier from a successful upload or duplicate response.","example":"7ad2c50d-2cc0-49a0-9a9c-6fa817c1fbcb"},"required":true,"description":"Invoice identifier from a successful upload or duplicate response.","name":"invoice_id","in":"path"}],"responses":{"200":{"description":"Current invoice processing and aggregate alert-assessment state.","headers":{"Cache-Control":{"schema":{"type":"string","example":"no-store"},"description":"Prevents a changing polling response from being cached."},"Retry-After":{"schema":{"type":"string","example":"10"},"description":"Seconds before polling again. Present exactly while either processing status is `pending` or `processing`."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvoiceStatusResponse"},"examples":{"processing":{"summary":"Invoice processing is underway","value":{"invoice_id":"7ad2c50d-2cc0-49a0-9a9c-6fa817c1fbcb","invoice_number":null,"processing":{"status":"processing","classification":null,"failure":null},"alerts":{"processing":{"status":"pending","skip_reason":null,"failure":null},"result":null,"count":null,"resolution":null},"invoice_url":"https://app.watchdog.no/org_3AFsEYath1408oAK0EkJikS8qp1/invoices/7ad2c50d-2cc0-49a0-9a9c-6fa817c1fbcb","created_at":"2026-08-12T07:44:20.000Z"}},"assessmentProcessing":{"summary":"Assessment is underway with alerts detected so far","value":{"invoice_id":"7ad2c50d-2cc0-49a0-9a9c-6fa817c1fbcb","invoice_number":"100234","processing":{"status":"completed","classification":"invoice","failure":null},"alerts":{"processing":{"status":"processing","skip_reason":null,"failure":null},"result":"alerts_found","count":2,"resolution":{"status":"open","method":null}},"invoice_url":"https://app.watchdog.no/org_3AFsEYath1408oAK0EkJikS8qp1/invoices/7ad2c50d-2cc0-49a0-9a9c-6fa817c1fbcb","created_at":"2026-08-12T07:44:20.000Z"}},"alertsFound":{"summary":"Assessment completed with alerts","value":{"invoice_id":"7ad2c50d-2cc0-49a0-9a9c-6fa817c1fbcb","invoice_number":"100234","processing":{"status":"completed","classification":"invoice","failure":null},"alerts":{"processing":{"status":"completed","skip_reason":null,"failure":null},"result":"alerts_found","count":7,"resolution":{"status":"open","method":null}},"invoice_url":"https://app.watchdog.no/org_3AFsEYath1408oAK0EkJikS8qp1/invoices/7ad2c50d-2cc0-49a0-9a9c-6fa817c1fbcb","created_at":"2026-08-12T07:44:20.000Z"}},"noAlerts":{"summary":"Assessment completed without alerts","value":{"invoice_id":"7ad2c50d-2cc0-49a0-9a9c-6fa817c1fbcb","invoice_number":"100234","processing":{"status":"completed","classification":"invoice","failure":null},"alerts":{"processing":{"status":"completed","skip_reason":null,"failure":null},"result":"no_alerts_found","count":0,"resolution":null},"invoice_url":"https://app.watchdog.no/org_3AFsEYath1408oAK0EkJikS8qp1/invoices/7ad2c50d-2cc0-49a0-9a9c-6fa817c1fbcb","created_at":"2026-08-12T07:44:20.000Z"}},"partialFailure":{"summary":"Some checks failed after other checks found alerts","value":{"invoice_id":"7ad2c50d-2cc0-49a0-9a9c-6fa817c1fbcb","invoice_number":"100234","processing":{"status":"completed","classification":"invoice","failure":null},"alerts":{"processing":{"status":"failed","skip_reason":null,"failure":{"code":"some_alert_checks_failed","message":"Some agreement checks could not be completed."}},"result":"alerts_found","count":2,"resolution":{"status":"open","method":null}},"invoice_url":"https://app.watchdog.no/org_3AFsEYath1408oAK0EkJikS8qp1/invoices/7ad2c50d-2cc0-49a0-9a9c-6fa817c1fbcb","created_at":"2026-08-12T07:44:20.000Z"}},"notInvoice":{"summary":"Document was not an invoice","value":{"invoice_id":"7ad2c50d-2cc0-49a0-9a9c-6fa817c1fbcb","invoice_number":null,"processing":{"status":"completed","classification":"not_invoice","failure":null},"alerts":{"processing":{"status":"skipped","skip_reason":"not_an_invoice","failure":null},"result":null,"count":null,"resolution":null},"invoice_url":"https://app.watchdog.no/org_3AFsEYath1408oAK0EkJikS8qp1/invoices/7ad2c50d-2cc0-49a0-9a9c-6fa817c1fbcb","created_at":"2026-08-12T07:44:20.000Z"}},"noApplicableAgreements":{"summary":"No applicable agreements","value":{"invoice_id":"7ad2c50d-2cc0-49a0-9a9c-6fa817c1fbcb","invoice_number":"100234","processing":{"status":"completed","classification":"invoice","failure":null},"alerts":{"processing":{"status":"skipped","skip_reason":"no_applicable_agreements","failure":null},"result":null,"count":null,"resolution":null},"invoice_url":"https://app.watchdog.no/org_3AFsEYath1408oAK0EkJikS8qp1/invoices/7ad2c50d-2cc0-49a0-9a9c-6fa817c1fbcb","created_at":"2026-08-12T07:44:20.000Z"}},"creditNote":{"summary":"Document is a credit note","value":{"invoice_id":"7ad2c50d-2cc0-49a0-9a9c-6fa817c1fbcb","invoice_number":"CN-100234","processing":{"status":"completed","classification":"credit_note","failure":null},"alerts":{"processing":{"status":"skipped","skip_reason":"credit_note","failure":null},"result":null,"count":null,"resolution":null},"invoice_url":"https://app.watchdog.no/org_3AFsEYath1408oAK0EkJikS8qp1/invoices/7ad2c50d-2cc0-49a0-9a9c-6fa817c1fbcb","created_at":"2026-08-12T07:44:20.000Z"}},"creditNoteMatched":{"summary":"Assessment was pre-empted by a matched credit note","value":{"invoice_id":"7ad2c50d-2cc0-49a0-9a9c-6fa817c1fbcb","invoice_number":"100234","processing":{"status":"completed","classification":"invoice","failure":null},"alerts":{"processing":{"status":"skipped","skip_reason":"credit_note_matched","failure":null},"result":null,"count":null,"resolution":null},"invoice_url":"https://app.watchdog.no/org_3AFsEYath1408oAK0EkJikS8qp1/invoices/7ad2c50d-2cc0-49a0-9a9c-6fa817c1fbcb","created_at":"2026-08-12T07:44:20.000Z"}},"invoiceFailure":{"summary":"Invoice processing failed","value":{"invoice_id":"7ad2c50d-2cc0-49a0-9a9c-6fa817c1fbcb","invoice_number":null,"processing":{"status":"failed","classification":null,"failure":{"code":"invoice_processing_failed","message":"Watchdog could not process this document."}},"alerts":{"processing":{"status":"skipped","skip_reason":"invoice_processing_failed","failure":null},"result":null,"count":null,"resolution":null},"invoice_url":"https://app.watchdog.no/org_3AFsEYath1408oAK0EkJikS8qp1/invoices/7ad2c50d-2cc0-49a0-9a9c-6fa817c1fbcb","created_at":"2026-08-12T07:44:20.000Z"}},"creditNoteResolution":{"summary":"Detected alerts were resolved by a credit note","value":{"invoice_id":"7ad2c50d-2cc0-49a0-9a9c-6fa817c1fbcb","invoice_number":"100234","processing":{"status":"completed","classification":"invoice","failure":null},"alerts":{"processing":{"status":"completed","skip_reason":null,"failure":null},"result":"alerts_found","count":7,"resolution":{"status":"resolved","method":"credit_note"}},"invoice_url":"https://app.watchdog.no/org_3AFsEYath1408oAK0EkJikS8qp1/invoices/7ad2c50d-2cc0-49a0-9a9c-6fa817c1fbcb","created_at":"2026-08-12T07:44:20.000Z"}},"manualReviewResolution":{"summary":"Detected alerts were resolved through manual review","value":{"invoice_id":"7ad2c50d-2cc0-49a0-9a9c-6fa817c1fbcb","invoice_number":"100234","processing":{"status":"completed","classification":"invoice","failure":null},"alerts":{"processing":{"status":"completed","skip_reason":null,"failure":null},"result":"alerts_found","count":2,"resolution":{"status":"resolved","method":"manual_review"}},"invoice_url":"https://app.watchdog.no/org_3AFsEYath1408oAK0EkJikS8qp1/invoices/7ad2c50d-2cc0-49a0-9a9c-6fa817c1fbcb","created_at":"2026-08-12T07:44:20.000Z"}}}}}},"400":{"description":"The invoice ID is not a valid UUID.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody_validation_error"}}}},"401":{"description":"Authentication failed — missing, malformed, unknown, or revoked token. See `WWW-Authenticate` header per RFC 6750.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody_invalid_token"}}}},"403":{"description":"Token is disabled (operator-controlled kill switch) or lacks the required scope.","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ErrorBody_token_disabled"},{"$ref":"#/components/schemas/ErrorBody_insufficient_scope"}]}}}},"404":{"description":"Invoice not found. Missing, deleted, and cross-organization IDs are identical.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody_not_found"}}}},"429":{"description":"Rate limit exceeded. Pre-auth IP cap is 300 req/min; per-token cap is 120 req/min. Response headers indicate when the caller may retry.","headers":{"Retry-After":{"description":"Seconds until the caller may retry. Only present on 429 responses.","schema":{"type":"string","example":"34"}},"X-RateLimit-Limit":{"description":"Maximum requests allowed in the current window.","schema":{"type":"string","example":"300"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current window.","schema":{"type":"string","example":"0"}},"X-RateLimit-Reset":{"description":"Unix timestamp in seconds when the current window resets. Divide by 1000 if you have a millisecond-precision clock.","schema":{"type":"string","example":"1713793234"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody_rate_limit_exceeded"}}}},"500":{"description":"Internal error reading invoice status.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody_internal_error"}}}}}}}},"webhooks":{}}