myorlen-ebok-api 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- myorlen_ebok_api-0.1.0/.gitignore +22 -0
- myorlen_ebok_api-0.1.0/AGENTS.md +91 -0
- myorlen_ebok_api-0.1.0/API.md +142 -0
- myorlen_ebok_api-0.1.0/LICENSE +21 -0
- myorlen_ebok_api-0.1.0/PKG-INFO +123 -0
- myorlen_ebok_api-0.1.0/README.md +101 -0
- myorlen_ebok_api-0.1.0/pyproject.toml +69 -0
- myorlen_ebok_api-0.1.0/src/myorlen_ebok_api/__init__.py +66 -0
- myorlen_ebok_api-0.1.0/src/myorlen_ebok_api/__main__.py +3 -0
- myorlen_ebok_api-0.1.0/src/myorlen_ebok_api/cli.py +184 -0
- myorlen_ebok_api-0.1.0/src/myorlen_ebok_api/client.py +519 -0
- myorlen_ebok_api-0.1.0/src/myorlen_ebok_api/exceptions.py +29 -0
- myorlen_ebok_api-0.1.0/src/myorlen_ebok_api/models.py +318 -0
- myorlen_ebok_api-0.1.0/src/myorlen_ebok_api/parsers.py +479 -0
- myorlen_ebok_api-0.1.0/src/myorlen_ebok_api/py.typed +0 -0
- myorlen_ebok_api-0.1.0/tests/__init__.py +0 -0
- myorlen_ebok_api-0.1.0/tests/conftest.py +63 -0
- myorlen_ebok_api-0.1.0/tests/fixtures/account_history.json +36 -0
- myorlen_ebok_api-0.1.0/tests/fixtures/agreement_details.json +105 -0
- myorlen_ebok_api-0.1.0/tests/fixtures/agreements.json +104 -0
- myorlen_ebok_api-0.1.0/tests/fixtures/billing_summary.json +11 -0
- myorlen_ebok_api-0.1.0/tests/fixtures/client_payments.json +193 -0
- myorlen_ebok_api-0.1.0/tests/fixtures/contact_history.json +11 -0
- myorlen_ebok_api-0.1.0/tests/fixtures/email_notif.json +13 -0
- myorlen_ebok_api-0.1.0/tests/fixtures/invoice_details.json +61 -0
- myorlen_ebok_api-0.1.0/tests/fixtures/invoices.json +532 -0
- myorlen_ebok_api-0.1.0/tests/fixtures/invoices_p2.json +102 -0
- myorlen_ebok_api-0.1.0/tests/fixtures/monthly.json +23 -0
- myorlen_ebok_api-0.1.0/tests/fixtures/note_details.json +40 -0
- myorlen_ebok_api-0.1.0/tests/fixtures/notifications.json +43 -0
- myorlen_ebok_api-0.1.0/tests/fixtures/ppg_list.json +46 -0
- myorlen_ebok_api-0.1.0/tests/fixtures/reading_dates.json +13 -0
- myorlen_ebok_api-0.1.0/tests/fixtures/readings.json +78 -0
- myorlen_ebok_api-0.1.0/tests/fixtures/related.json +22 -0
- myorlen_ebok_api-0.1.0/tests/fixtures/unread.json +10 -0
- myorlen_ebok_api-0.1.0/tests/fixtures/user_data.json +64 -0
- myorlen_ebok_api-0.1.0/tests/fixtures/yearly.json +43 -0
- myorlen_ebok_api-0.1.0/tests/test_cli.py +150 -0
- myorlen_ebok_api-0.1.0/tests/test_client.py +317 -0
- myorlen_ebok_api-0.1.0/tests/test_live.py +78 -0
- myorlen_ebok_api-0.1.0/tests/test_parsers.py +203 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# credentials and personal downloads - never commit
|
|
2
|
+
.env
|
|
3
|
+
.env.*
|
|
4
|
+
session.json
|
|
5
|
+
*.pdf
|
|
6
|
+
*.xlsx
|
|
7
|
+
*.csv
|
|
8
|
+
|
|
9
|
+
# python / tooling
|
|
10
|
+
__pycache__/
|
|
11
|
+
*.py[cod]
|
|
12
|
+
.venv/
|
|
13
|
+
build/
|
|
14
|
+
dist/
|
|
15
|
+
*.egg-info/
|
|
16
|
+
.pytest_cache/
|
|
17
|
+
.mypy_cache/
|
|
18
|
+
.ruff_cache/
|
|
19
|
+
.coverage
|
|
20
|
+
coverage.xml
|
|
21
|
+
htmlcov/
|
|
22
|
+
.session/
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
Guidance for coding agents working on this repository.
|
|
4
|
+
|
|
5
|
+
## What this is
|
|
6
|
+
|
|
7
|
+
`myorlen-ebok-api`: an unofficial Python SDK + CLI for the myORLEN gas eBOK
|
|
8
|
+
(https://ebok.myorlen.pl; previously PGNiG eBOK at ebok.pgnig.pl). The portal is a React SPA over a JSON API
|
|
9
|
+
on the same host; the SDK logs in with e-mail + password, keeps the returned token and calls
|
|
10
|
+
the same endpoints. **API.md is the endpoint reference**: read it before touching the client,
|
|
11
|
+
and update it whenever you learn something new about the site.
|
|
12
|
+
|
|
13
|
+
## Layout
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
src/myorlen_ebok_api/
|
|
17
|
+
client.py MyorlenClient: login, token handling, one method per feature (I/O only)
|
|
18
|
+
parsers.py pure functions JSON -> models; all field names of the API live here
|
|
19
|
+
models.py dataclasses (Decimal money, date dates), InvoiceFilter enum, to_jsonable()
|
|
20
|
+
exceptions.py MyorlenError > AuthenticationError | ApiError | ParseError | NotFoundError
|
|
21
|
+
cli.py `myorlen-ebok-api` argparse CLI, JSON on stdout
|
|
22
|
+
tests/
|
|
23
|
+
fixtures/ ANONYMISED captures of real API responses
|
|
24
|
+
test_parsers.py parsers against fixtures
|
|
25
|
+
test_client.py client flows with HTTP mocked by `responses` (asserts request params too)
|
|
26
|
+
test_cli.py CLI end to end with mocked HTTP
|
|
27
|
+
test_live.py read-only checks against the real site, skipped unless MYORLEN_LIVE=1
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Commands
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
uv sync # install (uses uv.lock)
|
|
34
|
+
uv run pytest # offline test suite, must stay green
|
|
35
|
+
uv run ruff check . && uv run ruff format --check .
|
|
36
|
+
uv run mypy # strict mode on src/
|
|
37
|
+
MYORLEN_LIVE=1 uv run pytest -m live # needs MYORLEN_USER / MYORLEN_PASS (env or .env)
|
|
38
|
+
uv run myorlen-ebok-api --help # CLI
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Add dependencies with `uv add` / `uv add --dev` so `uv.lock` stays in sync. CI runs ruff,
|
|
42
|
+
mypy and pytest on Python 3.10–3.13 (`.github/workflows/ci.yml`).
|
|
43
|
+
|
|
44
|
+
## How a feature works (pattern to follow)
|
|
45
|
+
|
|
46
|
+
1. Find the route name in the web bundle (`https://ebok.myorlen.pl/static/js/main.js`): the
|
|
47
|
+
route table is `var H={auth:{…},crm:{…}}`, call sites look like
|
|
48
|
+
`Ct.getData("get_invoices_v2",{pageNumber:1,pageSize:12})` or `Ct.get("crm.get_ppg_list")`.
|
|
49
|
+
2. Call it through `MyorlenClient._get()` (adds `api-version=3.0` and the `AuthToken` header,
|
|
50
|
+
re-logs in once on 401, raises `ApiError` on a non-zero `Code`) or `_download()` for files.
|
|
51
|
+
3. Parse with a pure function in `parsers.py` into a dataclass from `models.py`.
|
|
52
|
+
|
|
53
|
+
Keep I/O in `client.py` and parsing in `parsers.py`. New parsers get a fixture + test in
|
|
54
|
+
`test_parsers.py`; new client methods get a `responses` test that also asserts the query sent
|
|
55
|
+
(see existing tests).
|
|
56
|
+
|
|
57
|
+
## Site quirks worth knowing
|
|
58
|
+
|
|
59
|
+
- Every call needs `api-version=3.0`; the token goes in the `AuthToken` header, not a cookie.
|
|
60
|
+
- Wrong credentials give `403` with an empty body, not a JSON error.
|
|
61
|
+
- The token expires after about an hour (sliding, see `TokenExpireDateUtc` in every answer);
|
|
62
|
+
the SDK caches it in the session file with a stable `DeviceId`.
|
|
63
|
+
- `get-user-data` may answer `Code: 1` on success.
|
|
64
|
+
- `get-invoices-v2` rejects `type=` with 400; use the boolean filters (API.md).
|
|
65
|
+
- `PdfExists` in invoice lists is always false; ask the PDF endpoint directly. Interest-note PDFs
|
|
66
|
+
often come back as `text/plain` "Brak podglądu PDF…" instead of a PDF.
|
|
67
|
+
- `get-interest-note-details` uses different field names than invoices (`DocumentNumber`,
|
|
68
|
+
`DateCreated`, `DatePaymentDeadline`).
|
|
69
|
+
|
|
70
|
+
## Releasing
|
|
71
|
+
|
|
72
|
+
Releases go to PyPI from GitHub Actions (`.github/workflows/release.yml`) via trusted
|
|
73
|
+
publishing; there is no token to manage.
|
|
74
|
+
|
|
75
|
+
1. Bump the version: `uv version --bump patch` (or `minor` / `major`); this updates `pyproject.toml` and `uv.lock`.
|
|
76
|
+
2. Commit, then tag and push: `git tag v$(uv version --short) && git push && git push --tags`.
|
|
77
|
+
3. The workflow runs CI, checks the tag matches the version, builds and smoke-tests the wheel,
|
|
78
|
+
publishes to https://pypi.org/project/myorlen-ebok-api/ and creates a GitHub release with the files attached.
|
|
79
|
+
|
|
80
|
+
PyPI versions can never be re-uploaded, so a broken release needs a new version number.
|
|
81
|
+
|
|
82
|
+
## Safety rules
|
|
83
|
+
|
|
84
|
+
- **Never commit personal data.** `.env` holds real credentials and is gitignored. Fixtures must
|
|
85
|
+
be anonymised: replace names, addresses, client / agreement / PPG / meter numbers, e-mails,
|
|
86
|
+
phone, PESEL, IBANs, document numbers, UUIDs and tokens before saving into `tests/fixtures/`.
|
|
87
|
+
Grep the fixtures for the real values before committing.
|
|
88
|
+
- Live exploration is read-only. Do not call payment endpoints (`pay-for-*`), reading
|
|
89
|
+
submission (`add-ppg-reading*`, `cancel-reading`), contact forms, agreement changes, e-invoice
|
|
90
|
+
toggles or account settings. If the SDK ever exposes a write endpoint, test it with mocks only.
|
|
91
|
+
- Keep request volume low when exploring (one login, reuse the token).
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# myORLEN eBOK (ebok.myorlen.pl, formerly PGNiG eBOK): reverse-engineered API reference
|
|
2
|
+
|
|
3
|
+
Mapped in November 2026 against a live household account (one gas agreement, tariff W-2.1)
|
|
4
|
+
and the web app bundle (`/static/js/main.js?v=1.1646`). Unofficial: the operator can change
|
|
5
|
+
any of this without notice. Implemented in `src/myorlen_ebok_api/client.py` (HTTP) and
|
|
6
|
+
`src/myorlen_ebok_api/parsers.py` (JSON parsing). All example values below are fake.
|
|
7
|
+
|
|
8
|
+
> **Host.** `https://ebok.pgnig.pl/` now redirects (301) to `https://ebok.myorlen.pl/`.
|
|
9
|
+
> Only the new host is used.
|
|
10
|
+
|
|
11
|
+
## Architecture
|
|
12
|
+
|
|
13
|
+
- `ebok.myorlen.pl` serves a **React SPA**; its JSON API lives on the same origin under
|
|
14
|
+
`/auth/…`, `/crm/…`, `/notification/…`, `/contact/…`, `/agreements/…`, `/cms/…`.
|
|
15
|
+
The bundle has the full route table (`var H={auth:{login:"/auth/login",…},crm:{…}}`).
|
|
16
|
+
- Every request carries the query parameter **`api-version=3.0`**.
|
|
17
|
+
- Authenticated requests send the token in the **`AuthToken`** request header (no cookies needed).
|
|
18
|
+
- JSON is PascalCase. Every answer has an envelope:
|
|
19
|
+
`Code` (0 = OK), `Message`, `DisplayToEndUser`, `EndUserMessage`, `TokenExpireDate`,
|
|
20
|
+
`TokenExpireDateUtc` (sliding token expiry), `ConfigUpdateDateUtc`.
|
|
21
|
+
`crm/get-user-data` can answer `Code: 1` on success (the web app treats it as 0).
|
|
22
|
+
- Timestamps: `2026-10-27T00:00:00.000000Z`. Query dates are sent as `Date.toISOString()`,
|
|
23
|
+
e.g. `2025-01-01T00:00:00.000Z`. Amounts are JSON numbers (PLN), volumes in m³, energy in kWh.
|
|
24
|
+
- Missing / invalid token → `401 {"Message": "Authorization has been denied for this request."}`.
|
|
25
|
+
- Bad request parameters → `400` with `Code: 1`.
|
|
26
|
+
|
|
27
|
+
## Authentication
|
|
28
|
+
|
|
29
|
+
`POST /auth/login?api-version=3.0`, JSON body:
|
|
30
|
+
|
|
31
|
+
```json
|
|
32
|
+
{"Identificator": "you@example.com", "AccessPin": "password",
|
|
33
|
+
"DeviceType": "Web", "DeviceId": "<uuid>", "DeviceName": "…"}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Success → `200` with `Token`, `DateExpirationUtc` (≈1 h), `AutomaticLoginToken` (for
|
|
37
|
+
`/auth/login-automatic-token`, "remember me"), flags (`NewUser`, `ForceChangePasswordByInvalidPolicy`, …).
|
|
38
|
+
Wrong credentials → `403` with an empty body. Other failures carry `Code`: 1011 unauthorised
|
|
39
|
+
device, 1015 user not found, 1018 not activated, 1025 temporarily blocked (5 minutes).
|
|
40
|
+
No captcha on this endpoint (the site has a reCAPTCHA key, used by other forms).
|
|
41
|
+
|
|
42
|
+
`DeviceId` shows up in the account's device list (`/auth/get-devices`); the SDK keeps it stable
|
|
43
|
+
in the session file. Logout: `POST /auth/logout` with `{}` and the `AuthToken` header.
|
|
44
|
+
|
|
45
|
+
The site also has an OpenID flow (`/auth/oid/init-login` → `RedirectUrl`), used for accounts
|
|
46
|
+
migrated to the shared ORLEN identity; the SDK uses the classic login above.
|
|
47
|
+
|
|
48
|
+
## Endpoints (all `GET`, all need `AuthToken`)
|
|
49
|
+
|
|
50
|
+
### Account
|
|
51
|
+
|
|
52
|
+
| Endpoint | Params | Response |
|
|
53
|
+
|---|---|---|
|
|
54
|
+
| `/crm/get-user-data` | – | `Email`, `FirstName`, `LastName`, `Pesel` (masked `800********`), `Nip`, `Saldo`, `AmountToPay`, `Billing`, `HasPrepaid`, `Acceptances[]` (consent texts), … |
|
|
55
|
+
| `/auth/get-related-accounts` | – | `RelatedAccounts[]`: `PublicId`, `ClientNumber`, `Current`, `ClientName`, `Pesel` |
|
|
56
|
+
| `/crm/get-other-accounts` | – | `Results[]`: other eBOK logins for the same PESEL (masked e-mail) |
|
|
57
|
+
| `/crm/get-billing-summary` | – | `{Status: "Paid", Value: null}` (dashboard headline) |
|
|
58
|
+
| `/crm/get-agreements` | – | `Agreements[]` (active) |
|
|
59
|
+
| `/crm/get-all-agreements` | – | `Agreements[]` incl. inactive |
|
|
60
|
+
| `/crm/get-agreement-details` | `agreementNumber`, `clientNumber` | `{Agreement: {...}}`, superset of the list item (+ `AddressForCorrespondence`, `FirstName`, `LastName`, `IsOwner`, `NotExpiredChanges`) |
|
|
61
|
+
| `/crm/get-ppg-list` | – | `PpgList[]`: `IdPPG`, `MeterNumber`, `Address`, `ReadingDateUtc`, `ReadingValue`, `ContractNumber`, `ClientNumber`, `Tariff`, `IdLocal`, `HasHistory`, `AddReadingMode`, … |
|
|
62
|
+
|
|
63
|
+
Agreement item: `Type` (`PPG` gas), `AgreementNumber`, `ClientNumber`, `PpNumber` (PPG
|
|
64
|
+
number), `Address` / `ClientAddress` / `InvoiceAddress` (`Ulica`, `UlicaTyp`, `NrBudynku`,
|
|
65
|
+
`NrLokalu`, `KodPocztowy`, `Miejscowosc`), `Active`, `StartDate`, `EndDate`, `ClientName`,
|
|
66
|
+
`Iban` (individual account to pay into), `EcoInvoice`, `Saldo`, `Region`, `Tariff`,
|
|
67
|
+
`AgreementName`, `Owner`, `CollectionPoints[]` (`NumberOSD`, `IdCRD`, `Address*`, `Billing`).
|
|
68
|
+
|
|
69
|
+
### Invoices
|
|
70
|
+
|
|
71
|
+
`/crm/get-invoices-v2`: `pageNumber`, `pageSize` (web app: 12; 200 for the payment dialog),
|
|
72
|
+
optional filters:
|
|
73
|
+
|
|
74
|
+
| Param | Meaning |
|
|
75
|
+
|---|---|
|
|
76
|
+
| `dateFrom`, `dateTo` | ISO timestamps, filter by issue date |
|
|
77
|
+
| `agreementNumber`, `clientNumber` | restrict to an agreement / customer |
|
|
78
|
+
| `paid=false` | unpaid only |
|
|
79
|
+
| `afterDeadline=true` | overdue |
|
|
80
|
+
| `loadAfter30Days=true` | forecast instalments due in more than 30 days |
|
|
81
|
+
| `excludeAfterDeadline=true` | not overdue ("upcoming" tab, combined with `paid=false`) |
|
|
82
|
+
| `beforeEndDate=true`, `forecastToPay=true`, `isHomeAssistant=true` | used by other screens |
|
|
83
|
+
|
|
84
|
+
`type=…` answers 400. Response: `InvoicesList[]`, `HasMoreRecords`, `AllowLoadAfter30Days`,
|
|
85
|
+
`AllowLoadAllInvoices`, `HasNonPaidForecast`. Item: `Number`, `Date`, `SellDate`,
|
|
86
|
+
`StartDate`/`EndDate` (billing period), `PayingDeadlineDate`, `GrossAmount`, `AmountToPay`,
|
|
87
|
+
`IsPaid`, `Status` (`Posted`), `Type`, `TempType` (`R` settlement, `P`/`B` forecast
|
|
88
|
+
instalments, empty for notes), `IsInterestNote`, `IsCreditNote`, `Correction`,
|
|
89
|
+
`AgreementNumber`, `IdPP`, `WearKWH`, `WearM3`, `Iban`, `PDFPrintAllowed`, `PdfExists`
|
|
90
|
+
(always false in practice; use the PDF endpoint).
|
|
91
|
+
|
|
92
|
+
| Endpoint | Params | Response |
|
|
93
|
+
|---|---|---|
|
|
94
|
+
| `/crm/get-invoice-details` | `invoiceNumber`, `excludePdfCheck=true` | `{Invoice: {...}}` + `Address`, `PdfVisibility`, `AutomaticPaymentDate`, `IsSubscribed` |
|
|
95
|
+
| `/crm/get-interest-note-details` | `interestNoteNumber`, `excludePdfCheck=true` | `{InterestNote: {DocumentNumber, DateCreated, DatePaymentDeadline, DateSell, GrossAmount, AmountToPay, IsPaid, …}}` |
|
|
96
|
+
| `/crm/get-invoice-pdf-visibility` | `invoiceNumber` | `{Visibility: "PdfVisible"}` |
|
|
97
|
+
| `/crm/get-invoice-pdf` | `invoiceNumber`, `mode=partial` | `application/pdf`, `Content-Disposition: inline; filename="p/…pdf"` |
|
|
98
|
+
| `/crm/get-interest-note-pdf` | `interestNoteNumber`, `mode=partial` | PDF, or `text/plain` "Brak podglądu PDF dla wybranej faktury." |
|
|
99
|
+
|
|
100
|
+
### Payments & history
|
|
101
|
+
|
|
102
|
+
| Endpoint | Params | Response |
|
|
103
|
+
|---|---|---|
|
|
104
|
+
| `/crm/get-client-payments` | – | `Payments[]`: `DocumentDate`, `DocumentNumber` (`KP/RAP/…`), `Value`, `PaymentType` (`P`), `Description`, `ClientNumber`, `Transfer` |
|
|
105
|
+
| `/crm/get-compensations` | – | `Compensations[]` (empty on the test account) |
|
|
106
|
+
| `/crm/get-refunds` | – | `Refunds[]` (empty on the test account) |
|
|
107
|
+
| `/crm/get-account-history` | `pageNumber`, `pageSize` | `HistoryList[]`: `Date`, `Type` ("Zapłata za fakturę", …), `Description` |
|
|
108
|
+
|
|
109
|
+
### Readings & consumption
|
|
110
|
+
|
|
111
|
+
| Endpoint | Params | Response |
|
|
112
|
+
|---|---|---|
|
|
113
|
+
| `/crm/get-all-ppg-readings-for-meter` | `idPpg`, `pageNumber`, `pageSize`, `ignoreStartDate=true` or `dateFrom`+`dateTo`, optional `type` | `MeterReadings[]`, `HasMoreRecords` |
|
|
114
|
+
| `/crm/get-ppg-readings-dates` | `idPpg` | `MeterReadingsDates[]` |
|
|
115
|
+
| `/crm/get-ppgs-readings-file` | `ppgIds` | xlsx attachment `Readings_YYYY_MM_DD_HH_MM_SS.xlsx` |
|
|
116
|
+
| `/crm/get-monthly-wear-chart-data` | `ppgIds`, `pageNumber`, `pageSize` | `ChartData: {"październik_2026": [{Label, Year, Value, Wear, Type, ReadingDateUtc, Period, ZoneLabel}]}` |
|
|
117
|
+
| `/crm/get-yearly-wear-chart-data` | `ppgIds` | `ComparisonPercent`, `IsPlusSignForPercent`, `ThisYearData[]` / `PreviousYearData[]`: `{Year, WearByYear, ChartItems[]}` |
|
|
118
|
+
| `/crm/get-wear-comparison-chart-data` | period params | not used |
|
|
119
|
+
|
|
120
|
+
Reading: `ReadingDateUtc`, `Value` (meter, m³), `Wear` (consumption since previous), `Value2/3`,
|
|
121
|
+
`Wear2/3` (multi-register meters), `Type` (`Real`, …), `Status` (`ROZL` settled,
|
|
122
|
+
`ANUL_KLIENT` cancelled by customer), `MeterNumber`, `PpId`, `ClientNumber`, `CanBeCancelled`.
|
|
123
|
+
The list only covers the current billing system's history (two readings on the test account).
|
|
124
|
+
|
|
125
|
+
### Messages & settings
|
|
126
|
+
|
|
127
|
+
| Endpoint | Params | Response |
|
|
128
|
+
|---|---|---|
|
|
129
|
+
| `/notification/get-notifications` | – | `Notifications[]`: `Id`, `Title`, `Body`, `DateCreatedUtc`, `Type` (`Invoices`, …), `ObjectId` (invoice number) |
|
|
130
|
+
| `/notification/get-unreaded-count` | – | `{UnreadedCount}` |
|
|
131
|
+
| `/notification/email-settings` | – | `{Settings: {System, Invoices}}` |
|
|
132
|
+
| `/contact/get-contact-history-v2` | `pageIndex`, `pageSize` | `Contacts[]`, `AllowLoadMore` (item shape not observed: empty on the test account) |
|
|
133
|
+
| `/contact/get-contact-message` | `PublicId` | `Answers`, `ContactMessage` (not used) |
|
|
134
|
+
|
|
135
|
+
## Write endpoints (not used by the SDK)
|
|
136
|
+
|
|
137
|
+
Mapped from the bundle only; never called while exploring:
|
|
138
|
+
`POST /crm/add-ppg-reading-v2` (submit a reading), `/crm/cancel-reading`,
|
|
139
|
+
`/crm/pay-for-invoice-v2` / `pay-for-multi-invoice-v2` (payments), `/notification/remove`,
|
|
140
|
+
`/agreements/set-agreement-name`, `/agreements/set-agreement-color`, `/cms/order-einvoice`,
|
|
141
|
+
`/crm/disable-eco-invoice`, `/contact/send-message-v2`, `/auth/change-password`,
|
|
142
|
+
`/auth/change-email-v2`, `/agreements/change-tariff`, `/agreements/send-terminate-agreement`.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jacek Grela
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: myorlen-ebok-api
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Unofficial Python SDK and CLI for the myORLEN gas eBOK (ebok.myorlen.pl, formerly PGNiG eBOK): agreements, invoices, PDFs, payments, meter readings, consumption.
|
|
5
|
+
Project-URL: Homepage, https://github.com/grelade/myorlen-ebok-api
|
|
6
|
+
Project-URL: Issues, https://github.com/grelade/myorlen-ebok-api/issues
|
|
7
|
+
Author-email: Jacek Grela <jacekgrela@gmail.com>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: ebok,gas,invoices,myorlen,pgnig,sdk
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Natural Language :: Polish
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
17
|
+
Classifier: Topic :: Home Automation
|
|
18
|
+
Classifier: Typing :: Typed
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
|
+
Requires-Dist: requests>=2.31
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
|
|
23
|
+
# myorlen-ebok-api
|
|
24
|
+
|
|
25
|
+
Unofficial Python SDK and command-line client for the **myORLEN eBOK**
|
|
26
|
+
([ebok.myorlen.pl](https://ebok.myorlen.pl)), the customer portal of the Polish gas retailer myORLEN.
|
|
27
|
+
|
|
28
|
+
> **Previous name: PGNiG eBOK.** The portal used to be the eBOK of PGNiG Obrót Detaliczny at
|
|
29
|
+
> `ebok.pgnig.pl`; after the rebranding to myORLEN that address redirects to `ebok.myorlen.pl`.
|
|
30
|
+
> Existing PGNiG eBOK logins work unchanged.
|
|
31
|
+
|
|
32
|
+
It logs in with your eBOK e-mail and password and gives typed access to what the portal shows:
|
|
33
|
+
|
|
34
|
+
- user data, balance and amount to pay, linked customer accounts
|
|
35
|
+
- supply agreements with tariff, address, IBAN, collection points; agreement details
|
|
36
|
+
- invoices, forecast instalments and interest notes (filters, paging), invoice details, **PDF downloads**
|
|
37
|
+
- payments booked on the account, eBOK action history
|
|
38
|
+
- gas meter points (PPG) with the last reading; reading history, Excel export
|
|
39
|
+
- consumption per settlement period and year-over-year comparison
|
|
40
|
+
- notifications, contact-form history, e-mail notification settings
|
|
41
|
+
|
|
42
|
+
> Not affiliated with PGNiG or ORLEN. The portal has no public API; this library calls the
|
|
43
|
+
> same JSON endpoints the web app uses and can break when they change.
|
|
44
|
+
> See [API.md](API.md) for the reverse-engineered endpoint reference.
|
|
45
|
+
|
|
46
|
+
## Install
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
pip install myorlen-ebok-api # or: uv add myorlen-ebok-api
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Latest unreleased code: `pip install git+https://github.com/grelade/myorlen-ebok-api`.
|
|
53
|
+
|
|
54
|
+
Requires Python 3.10+.
|
|
55
|
+
|
|
56
|
+
## Command line
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
export MYORLEN_USER=you@example.com MYORLEN_PASS='…' # or put them in ./.env (PGNIG_USER / PGNIG_PASS also work)
|
|
60
|
+
uvx myorlen-ebok-api balance
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
| Command | Output |
|
|
64
|
+
|---|---|
|
|
65
|
+
| `user`, `balance`, `accounts` | user data, balance / amount to pay / payment status, linked accounts |
|
|
66
|
+
| `agreements [--all]` / `agreement [NUMBER]` | supply agreements / details of one |
|
|
67
|
+
| `meter-points` | meter points (PPG) with the last reading |
|
|
68
|
+
| `invoices [--from D] [--to D] [--filter all\|unpaid\|overdue\|forecast] [--agreement N] [--limit N]` | invoices |
|
|
69
|
+
| `invoice NUMBER` | invoice or interest-note details |
|
|
70
|
+
| `pdf NUMBER [--out DIR_OR_FILE]` | save an invoice PDF |
|
|
71
|
+
| `payments`, `history [--limit N]` | payments, eBOK action history |
|
|
72
|
+
| `readings [--from D] [--to D] [--xlsx PATH]` | meter readings (m³) or the Excel export |
|
|
73
|
+
| `monthly [--months N]`, `yearly` | consumption charts |
|
|
74
|
+
| `notifications`, `contacts`, `email-settings` | messages and settings |
|
|
75
|
+
|
|
76
|
+
Output is JSON (amounts are strings to keep `Decimal` precision). Global options: `--ppg ID`
|
|
77
|
+
(needed only for accounts with several meter points) and `--session-file PATH` (default
|
|
78
|
+
`~/.cache/myorlen-ebok-api/session.json`; the token is reused so repeated runs don't log in again).
|
|
79
|
+
|
|
80
|
+
## Library
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
from myorlen_ebok_api import MyorlenClient
|
|
84
|
+
|
|
85
|
+
with MyorlenClient("you@example.com", "secret", session_file="~/.cache/myorlen-ebok-api/session.json") as c:
|
|
86
|
+
user = c.get_user()
|
|
87
|
+
print(user.balance, user.amount_to_pay)
|
|
88
|
+
|
|
89
|
+
for inv in c.iter_invoices(filter="unpaid"):
|
|
90
|
+
print(inv.number, inv.gross_amount, inv.due_date)
|
|
91
|
+
|
|
92
|
+
latest = next(c.iter_invoices())
|
|
93
|
+
pdf = c.download_invoice(latest) # DownloadedFile(filename, content_type, content)
|
|
94
|
+
open(pdf.filename, "wb").write(pdf.content)
|
|
95
|
+
|
|
96
|
+
for r in c.iter_readings():
|
|
97
|
+
print(r.date, r.value, r.consumption, "m³")
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
All methods: `get_user`, `get_related_accounts`, `get_billing_summary`, `get_agreements`,
|
|
101
|
+
`get_agreement`, `get_meter_points`, `get_meter_point`, `get_invoices`, `iter_invoices`,
|
|
102
|
+
`get_invoice`, `download_invoice`, `get_payments`, `get_account_history`, `get_readings`,
|
|
103
|
+
`iter_readings`, `get_reading_dates`, `export_readings`, `get_monthly_consumption`,
|
|
104
|
+
`get_yearly_consumption`, `get_notifications`, `get_unread_count`, `get_email_settings`,
|
|
105
|
+
`get_contact_history`, `iter_contact_history`; session: `login`, `logout`, `save_session`.
|
|
106
|
+
|
|
107
|
+
Errors derive from `myorlen_ebok_api.MyorlenError` (`AuthenticationError`, `ApiError`, `ParseError`,
|
|
108
|
+
`NotFoundError`).
|
|
109
|
+
|
|
110
|
+
## Development
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
uv sync # creates .venv with dev tools
|
|
114
|
+
uv run pytest # offline tests (HTTP mocked, anonymised fixtures)
|
|
115
|
+
uv run ruff check . && uv run ruff format --check . && uv run mypy
|
|
116
|
+
MYORLEN_LIVE=1 uv run pytest -m live # read-only smoke tests against the real site (.env credentials)
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
See [AGENTS.md](AGENTS.md) for the project layout and conventions.
|
|
120
|
+
|
|
121
|
+
## License
|
|
122
|
+
|
|
123
|
+
MIT
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# myorlen-ebok-api
|
|
2
|
+
|
|
3
|
+
Unofficial Python SDK and command-line client for the **myORLEN eBOK**
|
|
4
|
+
([ebok.myorlen.pl](https://ebok.myorlen.pl)), the customer portal of the Polish gas retailer myORLEN.
|
|
5
|
+
|
|
6
|
+
> **Previous name: PGNiG eBOK.** The portal used to be the eBOK of PGNiG Obrót Detaliczny at
|
|
7
|
+
> `ebok.pgnig.pl`; after the rebranding to myORLEN that address redirects to `ebok.myorlen.pl`.
|
|
8
|
+
> Existing PGNiG eBOK logins work unchanged.
|
|
9
|
+
|
|
10
|
+
It logs in with your eBOK e-mail and password and gives typed access to what the portal shows:
|
|
11
|
+
|
|
12
|
+
- user data, balance and amount to pay, linked customer accounts
|
|
13
|
+
- supply agreements with tariff, address, IBAN, collection points; agreement details
|
|
14
|
+
- invoices, forecast instalments and interest notes (filters, paging), invoice details, **PDF downloads**
|
|
15
|
+
- payments booked on the account, eBOK action history
|
|
16
|
+
- gas meter points (PPG) with the last reading; reading history, Excel export
|
|
17
|
+
- consumption per settlement period and year-over-year comparison
|
|
18
|
+
- notifications, contact-form history, e-mail notification settings
|
|
19
|
+
|
|
20
|
+
> Not affiliated with PGNiG or ORLEN. The portal has no public API; this library calls the
|
|
21
|
+
> same JSON endpoints the web app uses and can break when they change.
|
|
22
|
+
> See [API.md](API.md) for the reverse-engineered endpoint reference.
|
|
23
|
+
|
|
24
|
+
## Install
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pip install myorlen-ebok-api # or: uv add myorlen-ebok-api
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Latest unreleased code: `pip install git+https://github.com/grelade/myorlen-ebok-api`.
|
|
31
|
+
|
|
32
|
+
Requires Python 3.10+.
|
|
33
|
+
|
|
34
|
+
## Command line
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
export MYORLEN_USER=you@example.com MYORLEN_PASS='…' # or put them in ./.env (PGNIG_USER / PGNIG_PASS also work)
|
|
38
|
+
uvx myorlen-ebok-api balance
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
| Command | Output |
|
|
42
|
+
|---|---|
|
|
43
|
+
| `user`, `balance`, `accounts` | user data, balance / amount to pay / payment status, linked accounts |
|
|
44
|
+
| `agreements [--all]` / `agreement [NUMBER]` | supply agreements / details of one |
|
|
45
|
+
| `meter-points` | meter points (PPG) with the last reading |
|
|
46
|
+
| `invoices [--from D] [--to D] [--filter all\|unpaid\|overdue\|forecast] [--agreement N] [--limit N]` | invoices |
|
|
47
|
+
| `invoice NUMBER` | invoice or interest-note details |
|
|
48
|
+
| `pdf NUMBER [--out DIR_OR_FILE]` | save an invoice PDF |
|
|
49
|
+
| `payments`, `history [--limit N]` | payments, eBOK action history |
|
|
50
|
+
| `readings [--from D] [--to D] [--xlsx PATH]` | meter readings (m³) or the Excel export |
|
|
51
|
+
| `monthly [--months N]`, `yearly` | consumption charts |
|
|
52
|
+
| `notifications`, `contacts`, `email-settings` | messages and settings |
|
|
53
|
+
|
|
54
|
+
Output is JSON (amounts are strings to keep `Decimal` precision). Global options: `--ppg ID`
|
|
55
|
+
(needed only for accounts with several meter points) and `--session-file PATH` (default
|
|
56
|
+
`~/.cache/myorlen-ebok-api/session.json`; the token is reused so repeated runs don't log in again).
|
|
57
|
+
|
|
58
|
+
## Library
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
from myorlen_ebok_api import MyorlenClient
|
|
62
|
+
|
|
63
|
+
with MyorlenClient("you@example.com", "secret", session_file="~/.cache/myorlen-ebok-api/session.json") as c:
|
|
64
|
+
user = c.get_user()
|
|
65
|
+
print(user.balance, user.amount_to_pay)
|
|
66
|
+
|
|
67
|
+
for inv in c.iter_invoices(filter="unpaid"):
|
|
68
|
+
print(inv.number, inv.gross_amount, inv.due_date)
|
|
69
|
+
|
|
70
|
+
latest = next(c.iter_invoices())
|
|
71
|
+
pdf = c.download_invoice(latest) # DownloadedFile(filename, content_type, content)
|
|
72
|
+
open(pdf.filename, "wb").write(pdf.content)
|
|
73
|
+
|
|
74
|
+
for r in c.iter_readings():
|
|
75
|
+
print(r.date, r.value, r.consumption, "m³")
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
All methods: `get_user`, `get_related_accounts`, `get_billing_summary`, `get_agreements`,
|
|
79
|
+
`get_agreement`, `get_meter_points`, `get_meter_point`, `get_invoices`, `iter_invoices`,
|
|
80
|
+
`get_invoice`, `download_invoice`, `get_payments`, `get_account_history`, `get_readings`,
|
|
81
|
+
`iter_readings`, `get_reading_dates`, `export_readings`, `get_monthly_consumption`,
|
|
82
|
+
`get_yearly_consumption`, `get_notifications`, `get_unread_count`, `get_email_settings`,
|
|
83
|
+
`get_contact_history`, `iter_contact_history`; session: `login`, `logout`, `save_session`.
|
|
84
|
+
|
|
85
|
+
Errors derive from `myorlen_ebok_api.MyorlenError` (`AuthenticationError`, `ApiError`, `ParseError`,
|
|
86
|
+
`NotFoundError`).
|
|
87
|
+
|
|
88
|
+
## Development
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
uv sync # creates .venv with dev tools
|
|
92
|
+
uv run pytest # offline tests (HTTP mocked, anonymised fixtures)
|
|
93
|
+
uv run ruff check . && uv run ruff format --check . && uv run mypy
|
|
94
|
+
MYORLEN_LIVE=1 uv run pytest -m live # read-only smoke tests against the real site (.env credentials)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
See [AGENTS.md](AGENTS.md) for the project layout and conventions.
|
|
98
|
+
|
|
99
|
+
## License
|
|
100
|
+
|
|
101
|
+
MIT
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "myorlen-ebok-api"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Unofficial Python SDK and CLI for the myORLEN gas eBOK (ebok.myorlen.pl, formerly PGNiG eBOK): agreements, invoices, PDFs, payments, meter readings, consumption."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
license-files = ["LICENSE"]
|
|
8
|
+
authors = [{ name = "Jacek Grela", email = "jacekgrela@gmail.com" }]
|
|
9
|
+
requires-python = ">=3.10"
|
|
10
|
+
keywords = ["pgnig", "myorlen", "ebok", "gas", "invoices", "sdk"]
|
|
11
|
+
classifiers = [
|
|
12
|
+
"Development Status :: 3 - Alpha",
|
|
13
|
+
"Intended Audience :: Developers",
|
|
14
|
+
"Natural Language :: Polish",
|
|
15
|
+
"Operating System :: OS Independent",
|
|
16
|
+
"Programming Language :: Python :: 3",
|
|
17
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
18
|
+
"Topic :: Home Automation",
|
|
19
|
+
"Typing :: Typed",
|
|
20
|
+
]
|
|
21
|
+
dependencies = [
|
|
22
|
+
"requests>=2.31",
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
[project.urls]
|
|
26
|
+
Homepage = "https://github.com/grelade/myorlen-ebok-api"
|
|
27
|
+
Issues = "https://github.com/grelade/myorlen-ebok-api/issues"
|
|
28
|
+
|
|
29
|
+
[project.scripts]
|
|
30
|
+
myorlen-ebok-api = "myorlen_ebok_api.cli:main"
|
|
31
|
+
|
|
32
|
+
[dependency-groups]
|
|
33
|
+
dev = [
|
|
34
|
+
"mypy>=1.10",
|
|
35
|
+
"pytest>=8",
|
|
36
|
+
"pytest-cov>=5",
|
|
37
|
+
"responses>=0.25",
|
|
38
|
+
"ruff>=0.6",
|
|
39
|
+
"types-requests>=2.31",
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
[build-system]
|
|
43
|
+
requires = ["hatchling>=1.26"]
|
|
44
|
+
build-backend = "hatchling.build"
|
|
45
|
+
|
|
46
|
+
[tool.hatch.build.targets.sdist]
|
|
47
|
+
include = ["src", "tests", "API.md", "AGENTS.md", "README.md", "LICENSE"]
|
|
48
|
+
|
|
49
|
+
[tool.ruff]
|
|
50
|
+
line-length = 110
|
|
51
|
+
target-version = "py310"
|
|
52
|
+
|
|
53
|
+
[tool.ruff.lint]
|
|
54
|
+
select = ["E", "F", "W", "I", "B", "UP", "SIM", "RUF"]
|
|
55
|
+
ignore = ["RUF001", "RUF002", "RUF003"] # Polish text contains look-alike characters by design
|
|
56
|
+
|
|
57
|
+
[tool.mypy]
|
|
58
|
+
python_version = "3.10"
|
|
59
|
+
strict = true
|
|
60
|
+
files = ["src"]
|
|
61
|
+
|
|
62
|
+
[[tool.mypy.overrides]]
|
|
63
|
+
module = ["responses.*"]
|
|
64
|
+
ignore_missing_imports = true
|
|
65
|
+
|
|
66
|
+
[tool.pytest.ini_options]
|
|
67
|
+
testpaths = ["tests"]
|
|
68
|
+
addopts = "-ra"
|
|
69
|
+
markers = ["live: hits the real ebok.myorlen.pl (needs MYORLEN_USER/MYORLEN_PASS and MYORLEN_LIVE=1)"]
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"""Unofficial Python SDK for the myORLEN gas eBOK (ebok.myorlen.pl, formerly PGNiG eBOK)."""
|
|
2
|
+
|
|
3
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
4
|
+
|
|
5
|
+
from .client import BASE_URL, MyorlenClient
|
|
6
|
+
from .exceptions import ApiError, AuthenticationError, MyorlenError, NotFoundError, ParseError
|
|
7
|
+
from .models import (
|
|
8
|
+
Address,
|
|
9
|
+
Agreement,
|
|
10
|
+
BillingSummary,
|
|
11
|
+
CollectionPoint,
|
|
12
|
+
ConsumptionEntry,
|
|
13
|
+
ContactMessage,
|
|
14
|
+
DownloadedFile,
|
|
15
|
+
EmailSettings,
|
|
16
|
+
HistoryEntry,
|
|
17
|
+
Invoice,
|
|
18
|
+
InvoiceFilter,
|
|
19
|
+
InvoicePage,
|
|
20
|
+
MeterPoint,
|
|
21
|
+
Notification,
|
|
22
|
+
Payment,
|
|
23
|
+
Reading,
|
|
24
|
+
ReadingPage,
|
|
25
|
+
RelatedAccount,
|
|
26
|
+
User,
|
|
27
|
+
YearConsumption,
|
|
28
|
+
YearlyConsumption,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
try:
|
|
32
|
+
__version__ = version("myorlen-ebok-api")
|
|
33
|
+
except PackageNotFoundError: # pragma: no cover - running from a source tree
|
|
34
|
+
__version__ = "0.0.0"
|
|
35
|
+
|
|
36
|
+
__all__ = [
|
|
37
|
+
"BASE_URL",
|
|
38
|
+
"Address",
|
|
39
|
+
"Agreement",
|
|
40
|
+
"ApiError",
|
|
41
|
+
"AuthenticationError",
|
|
42
|
+
"BillingSummary",
|
|
43
|
+
"CollectionPoint",
|
|
44
|
+
"ConsumptionEntry",
|
|
45
|
+
"ContactMessage",
|
|
46
|
+
"DownloadedFile",
|
|
47
|
+
"EmailSettings",
|
|
48
|
+
"HistoryEntry",
|
|
49
|
+
"Invoice",
|
|
50
|
+
"InvoiceFilter",
|
|
51
|
+
"InvoicePage",
|
|
52
|
+
"MeterPoint",
|
|
53
|
+
"MyorlenClient",
|
|
54
|
+
"MyorlenError",
|
|
55
|
+
"NotFoundError",
|
|
56
|
+
"Notification",
|
|
57
|
+
"ParseError",
|
|
58
|
+
"Payment",
|
|
59
|
+
"Reading",
|
|
60
|
+
"ReadingPage",
|
|
61
|
+
"RelatedAccount",
|
|
62
|
+
"User",
|
|
63
|
+
"YearConsumption",
|
|
64
|
+
"YearlyConsumption",
|
|
65
|
+
"__version__",
|
|
66
|
+
]
|