> ## Documentation Index
> Fetch the complete documentation index at: https://docs.watchdog.no/llms.txt
> Use this file to discover all available pages before exploring further.

# Upload and poll invoices

> Implement invoice upload, duplicate handling, polling, and terminal-state interpretation.

Invoice ingestion is asynchronous. A successful upload creates an invoice resource; processing and agreement checks continue after the response.

## Upload an invoice

Send one `primary` file and optional `attachments` as `multipart/form-data`.

```bash theme={null}
curl --include https://api.watchdog.no/v1/invoices/upload \
  --request POST \
  --header "Authorization: Bearer $WATCHDOG_API_KEY" \
  --form "primary=@invoice.pdf" \
  --form "attachments=@purchase-order.pdf"
```

The primary document may be PDF, Peppol BIS Billing 3.0 XML, or Finvoice 3.0 XML. The generated endpoint reference contains the current size, count, and media-type limits.

A successful response returns `201 Created`, an `invoice_id`, and a `Location` header such as `/v1/invoices/{invoice_id}`.

## Poll the resource

```bash theme={null}
curl --include \
  "https://api.watchdog.no/v1/invoices/$INVOICE_ID" \
  --header "Authorization: Bearer $WATCHDOG_API_KEY"
```

The response contains two independent lifecycles:

* `processing.status` describes document and invoice processing.
* `alerts.processing.status` describes the aggregate assessment across applicable agreements.

Continue polling while either status is `pending` or `processing`. When the response includes `Retry-After`, wait for that number of seconds before the next request.

<Warning>
  `alerts.result`, `alerts.count`, or `alerts.resolution` is not an approval signal by itself. Always interpret it together with `alerts.processing.status`. A failed assessment is incomplete even when some alerts were already found.
</Warning>

## Handle duplicates

A repeated primary document returns `409 Conflict`. The error includes `existing_invoice_id`; fetch that resource instead of creating another invoice.

If the original invoice was soft-deleted, the response uses `primary_md5_locked_by_deleted_invoice`. An administrator must permanently remove the original before the same primary document can be accepted again.

## Treat terminal responses as snapshots

Even a completed response represents the current state, not an immutable event. Agreement edits, rechecks, alert review, replacements, or credit-note matching can change it later. Integrations that need later changes should fetch the resource on their own reconciliation cadence.
