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

# Bill upload

> Connect route where the user uploads a bill and Flatpeak reads the supplier and prices.

The user photographs each page of a recent electricity bill, or uploads a PDF. Flatpeak reads the supplier and prices and routes the session to the best connection the bill allows. There is no result screen.

Bill upload is offered through `BILL_UPLOAD` on [Unlisted supplier](/docs/energy-api/reference/connect/tariff/unlisted-supplier.md) and [Prices](/docs/energy-api/reference/connect/tariff/prices.md), for when the supplier is not listed or has no login. Login stays the primary path, so the upload is not offered on the supplier list or the login screen. A bill from a supplier that does not serve the address counts as not recognized, and a user who cancels the supplier login lands on `library_select`.

> [tab] Upload
>
> ![](https://mintcdn.com/flatpeak-d495c19e/2B6nWUU4-c2pSD3E/images/busbar/connect/bill-upload.png?fit=max\&auto=format\&n=2B6nWUU4-c2pSD3E\&q=85\&s=5483c38ff0654963e9d96b235831ff4b)

> [tab] Pages
>
> ![](https://mintcdn.com/flatpeak-d495c19e/2B6nWUU4-c2pSD3E/images/busbar/connect/bill-upload-pages.png?fit=max\&auto=format\&n=2B6nWUU4-c2pSD3E\&q=85\&s=687a8f422abe88f90a676576e8fe9a20)

> [tab] Reading
>
> ![](https://mintcdn.com/flatpeak-d495c19e/2B6nWUU4-c2pSD3E/images/busbar/connect/bill-upload-reading.png?fit=max\&auto=format\&n=2B6nWUU4-c2pSD3E\&q=85\&s=64d0e51a9e5d1719980dd1d1242dcb3c)

> [tab] Not recognized
>
> ![](https://mintcdn.com/flatpeak-d495c19e/2B6nWUU4-c2pSD3E/images/busbar/connect/bill-upload-not-recognized.png?fit=max\&auto=format\&n=2B6nWUU4-c2pSD3E\&q=85\&s=6950bc944704f8f1271795544b31508b)

> [tab] Code
>
> ```json Connect response theme={"system"}
> {
>   "connect_session": "cos_6587fa4362341be5b524de3b",
>   "route": "bill_upload",
>   "live_mode": false,
>   "actions": [
>     "PRICE_INPUT",
>     "BACK",
>     "CLOSE"
>   ],
>   "data": {
>     "device_type": "BATTERY_STORAGE",
>     "location": {
>       "timezone": "Europe/London",
>       "currency_code": "GBP"
>     },
>     "status": "AWAITING_UPLOAD",
>     "upload": {
>       "upload_id": "upl_6a3196d6e61a44f33f7307ed",
>       "page_urls": [
>         "https://uploads.flatpeak.com/connect/upl_6a3196d6e61a44f33f7307ed/1",
>         "https://uploads.flatpeak.com/connect/upl_6a3196d6e61a44f33f7307ed/2",
>         "https://uploads.flatpeak.com/connect/upl_6a3196d6e61a44f33f7307ed/3",
>         "https://uploads.flatpeak.com/connect/upl_6a3196d6e61a44f33f7307ed/4",
>         "https://uploads.flatpeak.com/connect/upl_6a3196d6e61a44f33f7307ed/5",
>         "https://uploads.flatpeak.com/connect/upl_6a3196d6e61a44f33f7307ed/6"
>       ],
>       "content_types": ["image/jpeg", "image/png", "image/heic", "application/pdf"],
>       "max_bytes": 20000000,
>       "time_expiry": "2026-09-29T10:45:00Z"
>     }
>   }
> }
> ```
>
> ```bash Your PUT of a page theme={"system"}
> curl --request PUT \
>   --url https://uploads.flatpeak.com/connect/upl_6a3196d6e61a44f33f7307ed/1 \
>   --header 'Content-Type: image/jpeg' \
>   --data-binary @page1.jpg
> ```
>
> ```bash Your POST to Connect (pages uploaded) theme={"system"}
> curl --request POST \
>   --url https://connect.flatpeak.com \
>   --header 'Content-Type: application/json' \
>   --data '{
>   "connect_session": "cos_6587fa4362341be5b524de3b",
>   "route": "bill_upload",
>   "data": {
>     "upload_id": "upl_6a3196d6e61a44f33f7307ed",
>     "pages": 2
>   }
> }'
> ```
>
> #### Flow
>
> | Step | Your app | Connect |
> | :- | :- | :- |
> | 1 | Show Upload. The user takes a photo or picks a file. After the first photo, show Pages: one thumbnail per page and Add another page | `AWAITING_UPLOAD` with six `page_urls` slots |
> | 2 | `PUT` page 1 to slot 1, page 2 to slot 2, and so on. Then POST `upload_id` and `pages` | `READING` with `retry_after_seconds` |
> | 3 | Show Reading. POST `REFRESH` every `retry_after_seconds` | The next route, or `FAILED` |
>
> #### Where it lands
>
> The best connection the bill allows wins.
>
> | The bill shows | `REFRESH` returns |
> | :- | :- |
> | A supplier with a login | [Redirects](/docs/energy-api/reference/connect/tariff/redirects.md) with the supplier preselected. The user logs in, or lands on Unlisted supplier if they cancel |
> | Unit rates, no login | [Prices](/docs/energy-api/reference/connect/tariff/prices.md) prefilled, with `data.source` `BILL` and `bill.date`, for the user to check and edit. Prices from a bill are a `MANUAL` connection and do not update by themselves |
> | Neither | `bill_upload` with `status` `FAILED` and a `reason` |
>
> #### Capturing pages
>
> A PDF takes one slot and carries its own pages, and each photo takes one slot. Before the `PUT`, downscale a photo to 2,500 px on its long edge at JPEG quality 0.85, and convert HEIC on the device. A 12 MP photo drops from about 4 MB to under 1 MB.
>
> | | Web or WebView | Native |
> | :- | :- | :- |
> | Camera | `<input type="file" accept="image/*" capture="environment">` | Camera |
> | File | `<input type="file" accept="image/*,application/pdf">` | Photo library or document picker |
> | Upload | `fetch(url, { method: "PUT", body: file, headers: { "Content-Type": file.type } })` | `URLSession` upload task |
>
> The upload host allows `PUT` from any origin, so a WebView needs no proxy.
>
> #### The `data` object
>
> | Field | Description |
> | :- | :- |
> | `status` | `AWAITING_UPLOAD`, `READING` or `FAILED`. A successful read leaves this route. |
> | `upload` | Present at `AWAITING_UPLOAD`. Each `page_urls` slot accepts one `PUT` of up to `max_bytes` in one of `content_types`, until `time_expiry`. |
> | `retry_after_seconds` | Present at `READING`. Wait this long before `REFRESH`. |
> | `reason` | Present at `FAILED`: `bill_not_readable`, `not_an_electricity_bill`, `bill_too_old` or `upload_expired`. |
> | `bill.date` | Carried on the route the read lands on: the bill date as read, `YYYY-MM-DD`, or `null`. Show it, so the user can judge how current the prices are. |
>
> Flatpeak reads only the supplier, unit rates, standing charges, taxes and bill date. It deletes the pages when the session leaves this route, and the client never receives them back.
>
> #### Actions
>
> | Action | Result |
> | :- | :- |
> | `REFRESH` | Offered at `READING`. Re-reads the status. |
> | `CANCEL` | Offered at `READING`. Stops reading and returns to the page that offered the upload. |
> | `RETRY` | Offered at `FAILED`. Returns `AWAITING_UPLOAD` with new `page_urls`. |
> | `PRICE_INPUT` | Returns [Prices](/docs/energy-api/reference/connect/tariff/prices.md) empty. |
> | `BACK` | Returns the previous page. |
> | `CLOSE` | Returns the `callback_url` set on the Connect session. |
>
> #### Errors
>
> | Error code | Description |
> | :- | :- |
> | `upload_id_unknown` | No upload with that ID on this session. |
> | `upload_incomplete` | Nothing was `PUT` to slot 1 before the POST. |
> | `pages_missing` | `pages` is higher than the number of slots that received a file. |
> | `pages_invalid` | `pages` is below 1 or above the number of slots. |
> | `upload_too_large` | A page exceeds `max_bytes`. |
> | `content_type_unsupported` | A page is not one of `content_types`. |
> | `data_json_invalid` | Data does not conform to the JSON schema. |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.