curl --request GET \
--url https://api.watchdog.no/v1/invoices/{invoice_id} \
--header 'Authorization: Bearer <token>'const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.watchdog.no/v1/invoices/{invoice_id}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.watchdog.no/v1/invoices/{invoice_id}"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text){
"invoice_id": "7ad2c50d-2cc0-49a0-9a9c-6fa817c1fbcb",
"invoice_number": null,
"duplicate_of_invoice_id": 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"
}Get invoice
Poll the invoice resource returned in the upload Location header or referenced by existing_invoice_id in a duplicate response.
The processing and alerts.processing objects have independent lifecycles. Continue polling while either status is pending or processing, and respect Retry-After before polling again.
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.
count contains detected, non-superseded alerts and may increase while assessment is active. Dismissed and credited alerts remain in the detected count, while resolution indicates whether the findings remain blocking: manual_review means every current alert is dismissed or credited and the invoice has no qualifying full credit note; credit_note means the invoice has a uniquely matched credit note that offsets its total including VAT within ±1 currency unit in the same currency. 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.
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.
This 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.
invoice_id is the stable API identifier. invoice_number is extracted metadata and must not be treated as unique.
A semantic duplicate remains a terminal, pollable upload resource: duplicate_of_invoice_id identifies the canonical invoice and alert processing is skipped with duplicate_invoice.
curl --request GET \
--url https://api.watchdog.no/v1/invoices/{invoice_id} \
--header 'Authorization: Bearer <token>'const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.watchdog.no/v1/invoices/{invoice_id}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.watchdog.no/v1/invoices/{invoice_id}"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text){
"invoice_id": "7ad2c50d-2cc0-49a0-9a9c-6fa817c1fbcb",
"invoice_number": null,
"duplicate_of_invoice_id": 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"
}Authorizations
Personal API key from Settings → Personal → API keys. Send X-Organization-Id with the target organization. Plaintext is shown once at creation and cannot be recovered. Header: Authorization: Bearer wdg_<token>.
Headers
Required for personal API keys. Target one organization you have access to. Migrated keys may omit it to use their original organization. For Clerk sessions, it must match the active organization.
Path Parameters
Invoice identifier from a successful upload or duplicate response.
"7ad2c50d-2cc0-49a0-9a9c-6fa817c1fbcb"
Response
Current invoice processing and aggregate alert-assessment state.
Watchdog invoice identifier returned by the upload endpoint.
"7ad2c50d-2cc0-49a0-9a9c-6fa817c1fbcb"
Invoice number extracted from the document. For a semantic duplicate, this is the canonical invoice number. May be null before extraction or when no number can be identified; it is not a unique identifier.
"100234"
Canonical invoice identifier when this accepted upload was quarantined as a semantic duplicate; otherwise null.
null
- Option 1
- Option 2
- Option 3
Show child attributes
Show child attributes
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.
- Option 1
- Option 2
- Option 3
- Option 4
- Option 5
- Option 6
- Option 7
Show child attributes
Show child attributes
Absolute URL for reviewing the invoice and its alerts in Watchdog. For a semantic duplicate, this opens the canonical invoice.
"https://app.watchdog.no/org_3AFsEYath1408oAK0EkJikS8qp1/invoices/7ad2c50d-2cc0-49a0-9a9c-6fa817c1fbcb"
When the invoice resource was created.
"2026-08-12T07:44:20.000Z"