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

# Document upload

> Upload utility bill PDFs and images for processing via the Nectar API.

In addition to automatic bill collection via [connections](/developer-guide/getting-started#connection), you can upload documents directly through the API. This is useful for historical bills, one-off documents, or bills from utilities that don't have online portals.

## How document upload works

1. You submit one or more file URLs to the bulk upload endpoint.
2. Nectar queues each file for processing.
3. A **job ID** is returned that you can poll for status.
4. When processing completes, documents and usage data appear in the API like any other bill.

## Upload documents

Use the bulk upload endpoint to submit files for a company. Provide a `documents` array of publicly accessible HTTPS URLs and an optional `siteId` to assign the documents to a site.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST 'https://external.nectarclimate.com/v2.2/job/company/{companyId}/bulk' \
    -H 'X-API-Key: YOUR_SECRET_KEY' \
    -H 'Content-Type: application/json' \
    -d '{
      "documents": [
        "https://your-storage.com/bills/jan-2025-electric.pdf",
        "https://your-storage.com/bills/feb-2025-electric.pdf"
      ],
      "siteId": "{siteId}"
    }'
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
      f"https://external.nectarclimate.com/v2.2/job/company/{company_id}/bulk",
      headers={
          "X-API-Key": "YOUR_SECRET_KEY",
          "Content-Type": "application/json",
      },
      json={
          "documents": [
              "https://your-storage.com/bills/jan-2025-electric.pdf",
              "https://your-storage.com/bills/feb-2025-electric.pdf",
          ],
          "siteId": site_id,
      },
  )
  jobs = response.json()
  ```
</CodeGroup>

### Request fields

| Field       | Type             | Required | Description                                    |
| ----------- | ---------------- | -------- | ---------------------------------------------- |
| `documents` | Array of strings | Yes      | HTTPS URLs where Nectar can download each file |
| `siteId`    | UUID             | No       | Site to assign the uploaded documents to       |

## Upload a single file

You can also upload a single file directly as a form submission.

```bash theme={null}
curl -X POST 'https://external.nectarclimate.com/v2.2/job/company/{companyId}' \
  -H 'X-API-Key: YOUR_SECRET_KEY' \
  -F 'document=@/path/to/bill.pdf' \
  -F 'siteId={siteId}'
```

## Check job status

After uploading, poll the job detail endpoint to check processing status.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET 'https://external.nectarclimate.com/v2.2/job/{jobId}' \
    -H 'X-API-Key: YOUR_SECRET_KEY'
  ```

  ```python Python theme={null}
  response = requests.get(
      f"https://external.nectarclimate.com/v2.2/job/{job_id}",
      headers={"X-API-Key": "YOUR_SECRET_KEY"},
  )
  job = response.json()
  print(job["status"])
  ```
</CodeGroup>

### Job status values

| Status      | Description                                                                             |
| ----------- | --------------------------------------------------------------------------------------- |
| `PENDING`   | Job is queued or in progress                                                            |
| `COMPLETED` | Processing finished successfully                                                        |
| `FAILED`    | Processing failed — email [support@nectarclimate.com](mailto:support@nectarclimate.com) |

When a job completes, the response includes additional fields:

| Field                   | Type    | Description                                 |
| ----------------------- | ------- | ------------------------------------------- |
| `parsedDocumentIds`     | Array   | IDs of successfully processed documents     |
| `duplicateDocumentIds`  | Array   | IDs of documents identified as duplicates   |
| `duplicates`            | Integer | Count of duplicate documents                |
| `nonUtilityDocumentIds` | Array   | IDs of documents that are not utility bills |
| `terminationReason`     | String  | Reason for termination (if applicable)      |

## List jobs for a company

Retrieve all upload jobs for a company to monitor bulk processing progress.

```bash theme={null}
curl -X GET 'https://external.nectarclimate.com/v2.2/job/company/{companyId}' \
  -H 'X-API-Key: YOUR_SECRET_KEY'
```

## Supported file formats

| Format | Extension       | Notes                                             |
| ------ | --------------- | ------------------------------------------------- |
| PDF    | `.pdf`          | Most common format; supports multi-page documents |
| PNG    | `.png`          | Image of a utility bill                           |
| JPG    | `.jpg`, `.jpeg` | Image of a utility bill                           |

## Tips

* All URLs in the `documents` array must start with `https://`. If your files are in a private S3 bucket, generate a pre-signed URL.
* Include `siteId` to help Nectar assign the extracted data to the correct location.
* Processing typically completes within a few minutes per document.
* Once processed, the documents appear in the standard `/document/` endpoints and trigger `document.created.v2` [webhooks](/developer-guide/webhooks) if configured.

## Next steps

<CardGroup cols={3}>
  <Card title="Webhooks" icon="bell" href="/developer-guide/webhooks">
    Get notified when documents finish processing
  </Card>

  <Card title="Pagination" icon="arrow-right" href="/developer-guide/pagination">
    Iterate through document lists
  </Card>

  <Card title="Data model" icon="diagram-project" href="/developer-guide/data-model/overview">
    Understand how documents relate to usage data
  </Card>
</CardGroup>
