useyona-einvoice 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.
- useyona_einvoice-0.1.0/.gitignore +14 -0
- useyona_einvoice-0.1.0/CHANGELOG.md +28 -0
- useyona_einvoice-0.1.0/LICENSE +21 -0
- useyona_einvoice-0.1.0/PKG-INFO +352 -0
- useyona_einvoice-0.1.0/README.md +320 -0
- useyona_einvoice-0.1.0/pyproject.toml +82 -0
- useyona_einvoice-0.1.0/src/useyona/einvoice/__init__.py +97 -0
- useyona_einvoice-0.1.0/src/useyona/einvoice/_base.py +82 -0
- useyona_einvoice-0.1.0/src/useyona/einvoice/_transport.py +399 -0
- useyona_einvoice-0.1.0/src/useyona/einvoice/_version.py +3 -0
- useyona_einvoice-0.1.0/src/useyona/einvoice/client.py +152 -0
- useyona_einvoice-0.1.0/src/useyona/einvoice/errors.py +185 -0
- useyona_einvoice-0.1.0/src/useyona/einvoice/excluded_operations.py +30 -0
- useyona_einvoice-0.1.0/src/useyona/einvoice/py.typed +0 -0
- useyona_einvoice-0.1.0/src/useyona/einvoice/services/__init__.py +52 -0
- useyona_einvoice-0.1.0/src/useyona/einvoice/services/billing.py +136 -0
- useyona_einvoice-0.1.0/src/useyona/einvoice/services/catalogue.py +86 -0
- useyona_einvoice-0.1.0/src/useyona/einvoice/services/invoices.py +126 -0
- useyona_einvoice-0.1.0/src/useyona/einvoice/services/organization.py +36 -0
- useyona_einvoice-0.1.0/src/useyona/einvoice/services/output.py +44 -0
- useyona_einvoice-0.1.0/src/useyona/einvoice/services/parties.py +89 -0
- useyona_einvoice-0.1.0/src/useyona/einvoice/services/received.py +61 -0
- useyona_einvoice-0.1.0/src/useyona/einvoice/services/webhooks.py +81 -0
- useyona_einvoice-0.1.0/src/useyona/einvoice/types/__init__.py +130 -0
- useyona_einvoice-0.1.0/src/useyona/einvoice/types/generated.py +3825 -0
- useyona_einvoice-0.1.0/src/useyona/einvoice/types/webhook.py +174 -0
- useyona_einvoice-0.1.0/src/useyona/einvoice/webhooks.py +170 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file. The format is based on
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
5
|
+
|
|
6
|
+
## 0.1.0 (2026-10-07)
|
|
7
|
+
|
|
8
|
+
The first release of the Python SDK, at parity with `@useyona/einvoice-js` 0.8.1: 99 methods in 23
|
|
9
|
+
modules over the 106 operations an API key may call, 8 documented exclusions. The SDKs are versioned
|
|
10
|
+
independently; the einvoice-js commit pinned in `scripts/sync.sh` records which JS source this one tracks.
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- `EInvoice(api_key, ...)`: the mode follows the key prefix (`sk_test_` sandbox, `sk_live_` live) on
|
|
15
|
+
one permanent host; `assert_mode`, `timeout` (seconds), `retry=RetryConfig(...)`, `headers`,
|
|
16
|
+
`http_client` (an `httpx.Client`, e.g. with `httpx.MockTransport` in tests); context manager.
|
|
17
|
+
- Modules `invoices`, `submissions`, `output`, `share_links`, `items`, `reference`, `buyers`, `sellers`,
|
|
18
|
+
`inbound_invoices`, `issued_history`, `invoice_settings`, `tax_connection`, `organization`,
|
|
19
|
+
`billing.{accounts, payments, sandbox, statements, subscriptions, transactions}`,
|
|
20
|
+
`webhooks.{endpoints, deliveries, events, event_types}`; `paginate()`.
|
|
21
|
+
- The error hierarchy (`EInvoiceApiError` and its subclasses by status, `EInvoiceTimeoutError`,
|
|
22
|
+
`EInvoiceConnectionError`, `EInvoiceConfigError`, `EInvoiceWebhookError`).
|
|
23
|
+
- Retries with backoff and `Retry-After` for GET/PUT/DELETE and keyed writes; generated
|
|
24
|
+
`Idempotency-Key`s on the routes that accept one; one deadline per attempt covering headers and body.
|
|
25
|
+
- `useyona.einvoice.webhooks`: `verify_webhook`, `sign_webhook_payload`, `compute_webhook_signature`,
|
|
26
|
+
`parse_signature_header`, verified against the backend's test vectors.
|
|
27
|
+
- Generated `TypedDict` models for every request and response shape (`useyona.einvoice.types`).
|
|
28
|
+
- The five guide recipes in `examples/` and their export to `guides/guides.json`.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Elyonar
|
|
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,352 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: useyona-einvoice
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Official Python SDK for the Yona e-invoicing API — what an API key may call: invoicing, submissions to the tax authority, buyers, items, received invoices, billing reads and webhooks
|
|
5
|
+
Project-URL: Homepage, https://useyona.com/docs/sdks/python/installation
|
|
6
|
+
Project-URL: Repository, https://github.com/Elyonar/einvoice-python
|
|
7
|
+
Project-URL: Issues, https://github.com/Elyonar/einvoice-python/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/Elyonar/einvoice-python/blob/main/CHANGELOG.md
|
|
9
|
+
Author-email: Yona <dev@useyona.com>
|
|
10
|
+
License: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: api-client,billing,e-invoice,einvoice,electronic-invoice,invoice,nigeria,nrs,sdk,tax,tax-compliance,yona
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Office/Business :: Financial :: Accounting
|
|
22
|
+
Classifier: Typing :: Typed
|
|
23
|
+
Requires-Python: >=3.10
|
|
24
|
+
Requires-Dist: httpx<1,>=0.27
|
|
25
|
+
Requires-Dist: typing-extensions>=4.5
|
|
26
|
+
Provides-Extra: dev
|
|
27
|
+
Requires-Dist: mypy>=1.10; extra == 'dev'
|
|
28
|
+
Requires-Dist: pytest-cov>=5; extra == 'dev'
|
|
29
|
+
Requires-Dist: pytest>=8; extra == 'dev'
|
|
30
|
+
Requires-Dist: ruff>=0.5; extra == 'dev'
|
|
31
|
+
Description-Content-Type: text/markdown
|
|
32
|
+
|
|
33
|
+
# useyona-einvoice
|
|
34
|
+
|
|
35
|
+
Official Python SDK for the Yona e-invoicing API. It covers exactly what an API key may call:
|
|
36
|
+
invoicing, submissions to the tax authority, output and share links, items, reference data, buyers,
|
|
37
|
+
the read-only seller, received invoices and issued history, invoice settings, the tax connection, the
|
|
38
|
+
organisation (read), billing reads and webhooks (read, test, redeliver).
|
|
39
|
+
|
|
40
|
+
The same surface as [`@useyona/einvoice-js`](https://github.com/Elyonar/einvoice-js), module for
|
|
41
|
+
module, with the same names in `snake_case`.
|
|
42
|
+
|
|
43
|
+
## Features
|
|
44
|
+
|
|
45
|
+
- **One key, nothing else to configure.** `sk_test_…` is the sandbox, `sk_live_…` is live, on the same host.
|
|
46
|
+
- **Typed.** Every request and response shape is a `TypedDict` generated from the API's OpenAPI; `py.typed` ships.
|
|
47
|
+
- **Safe retries.** GET, PUT, DELETE and writes carrying an `Idempotency-Key` are retried on network
|
|
48
|
+
errors, timeouts, 408, 429 and 5xx, honouring `Retry-After`. The SDK generates the key on the
|
|
49
|
+
routes that accept one, so its own retry is never charged twice.
|
|
50
|
+
- **Typed errors.** `EInvoiceValidationError`, `EInvoiceNotFoundError`, `EInvoiceRateLimitError`… all
|
|
51
|
+
carry `status`, `error_code`, `errors`, `request_id` and `retry_after`.
|
|
52
|
+
- **Webhooks.** `verify_webhook` checks the `Yona-Signature` over the raw body in constant time.
|
|
53
|
+
- **Light.** `httpx` and `typing_extensions` are the only dependencies. Python 3.10+.
|
|
54
|
+
|
|
55
|
+
## Installation
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
pip install useyona-einvoice
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Quick start
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
import os
|
|
65
|
+
from useyona.einvoice import EInvoice
|
|
66
|
+
|
|
67
|
+
client = EInvoice(api_key=os.environ["YONA_API_KEY"])
|
|
68
|
+
client.mode # "sandbox" for sk_test_… keys, "live" for sk_live_… keys
|
|
69
|
+
|
|
70
|
+
# 1. A buyer
|
|
71
|
+
buyer = client.buyers.create(
|
|
72
|
+
{
|
|
73
|
+
"name": "Acme Nigeria Ltd",
|
|
74
|
+
"taxId": "12345678-0001",
|
|
75
|
+
"email": "accounts@acme.ng",
|
|
76
|
+
"partyType": "company",
|
|
77
|
+
"address": {"line1": "1 Marina", "city": "Lagos", "country": "NG"},
|
|
78
|
+
}
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
# 2. A saved item (optional: a line can also carry its own description, unit code and codes)
|
|
82
|
+
item = client.items.create(
|
|
83
|
+
{
|
|
84
|
+
"name": "Laptop",
|
|
85
|
+
"itemType": "goods",
|
|
86
|
+
"hsnCode": "8471.30",
|
|
87
|
+
"productCategory": "Machinery",
|
|
88
|
+
"unitCode": "EA",
|
|
89
|
+
"unitPriceMinor": "45000000",
|
|
90
|
+
"currency": "NGN",
|
|
91
|
+
"taxCategory": "STANDARD_VAT",
|
|
92
|
+
}
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
# 3. A draft invoice: invoiceKind and taxCategory, never taxPercent
|
|
96
|
+
invoice = client.invoices.create(
|
|
97
|
+
{
|
|
98
|
+
"invoiceKind": "B2B",
|
|
99
|
+
"invoiceDate": "2026-10-05",
|
|
100
|
+
"currency": "NGN",
|
|
101
|
+
"buyerId": buyer["id"],
|
|
102
|
+
"lineItems": [{"itemId": item["id"], "quantity": 2}],
|
|
103
|
+
}
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
# 4. Finalise and report it to the tax authority
|
|
107
|
+
client.invoices.finalise(invoice["id"])
|
|
108
|
+
client.submissions.submit(invoice["id"]) # 202: queued
|
|
109
|
+
status = client.submissions.get_status(invoice["id"])
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
That is all the configuration an integration needs: the key. The SDK talks to the production
|
|
113
|
+
gateway for both modes; the key's prefix decides whether you are in the sandbox or live.
|
|
114
|
+
|
|
115
|
+
To fail fast when a deployment is given the wrong key:
|
|
116
|
+
|
|
117
|
+
```python
|
|
118
|
+
EInvoice(api_key=key, assert_mode="live") # raises EInvoiceConfigError for an sk_test_ key
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
A malformed key is refused at construction with `EInvoiceConfigError` (the key is never echoed).
|
|
122
|
+
|
|
123
|
+
The client holds a connection pool; close it with `client.close()` or use it as a context manager
|
|
124
|
+
(`with EInvoice(api_key=key) as client:`).
|
|
125
|
+
|
|
126
|
+
## Guides
|
|
127
|
+
|
|
128
|
+
The recipes in [`examples/`](examples/) are the developer guides of the Yona portal (Developers,
|
|
129
|
+
Overview): your first invoice, webhooks, errors and retries, sandbox and live, received invoices.
|
|
130
|
+
Each runs end to end against a sandbox key (`YONA_API_KEY=sk_test_… make examples`).
|
|
131
|
+
|
|
132
|
+
## Verifying your setup
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
YONA_API_KEY=sk_test_… make smoke-remote
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
runs free reads across every module and then the first-invoice example against the real API, with
|
|
139
|
+
your own sandbox key, and prints a table method → OK/FAIL with the error code and request id of any
|
|
140
|
+
failure. It refuses a live key and never prints the key. The example creates sandbox data in your
|
|
141
|
+
organisation: a buyer, an item and an invoice submitted to the tax authority's sandbox.
|
|
142
|
+
|
|
143
|
+
## Responses and pagination
|
|
144
|
+
|
|
145
|
+
Methods return the API's `data` as a `TypedDict` with the wire names (`invoice["invoiceNumber"]`).
|
|
146
|
+
List methods return a `Page`:
|
|
147
|
+
|
|
148
|
+
```python
|
|
149
|
+
page = client.buyers.list({"limit": 50})
|
|
150
|
+
page.data # list[BuyerViewDto]
|
|
151
|
+
page.pagination # {"total", "page", "pageSize", "totalPages", "hasNext", "hasPrevious"}
|
|
152
|
+
page.request_id
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
`paginate` walks every page for you:
|
|
156
|
+
|
|
157
|
+
```python
|
|
158
|
+
from useyona.einvoice import paginate
|
|
159
|
+
|
|
160
|
+
for buyer in paginate(client.buyers.list, {"limit": 100}):
|
|
161
|
+
...
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Received invoices and issued history answer an object with `items`, so they return a `Paginated`:
|
|
165
|
+
`res.data["items"]` and `res.pagination`.
|
|
166
|
+
|
|
167
|
+
PDF downloads return a `BinaryResponse`: `data` (bytes), `content_type`, `file_name`, `request_id`.
|
|
168
|
+
|
|
169
|
+
## Errors
|
|
170
|
+
|
|
171
|
+
Every refusal of the API raises a subclass of `EInvoiceApiError`, chosen by status:
|
|
172
|
+
|
|
173
|
+
| Status | Class | Typical `error_code` |
|
|
174
|
+
|---|---|---|
|
|
175
|
+
| 400, 422 | `EInvoiceValidationError` | `VAL…` |
|
|
176
|
+
| 401 | `EInvoiceAuthenticationError` | `AUTH…` (a revoked, expired or malformed key) |
|
|
177
|
+
| 402 | `EInvoiceInsufficientCreditsError` | `BIZ001` |
|
|
178
|
+
| 403 | `EInvoicePermissionError` | `AUTH019` (capability), `AUTH018` (user-only route) |
|
|
179
|
+
| 404 | `EInvoiceNotFoundError` | `RES001` |
|
|
180
|
+
| 409 | `EInvoiceConflictError` | `BIZ…` (state), `RES002` (duplicate) |
|
|
181
|
+
| 429 | `EInvoiceRateLimitError` | `SYS005`, with `retry_after` |
|
|
182
|
+
| 5xx | `EInvoiceServerError` | `SYS001` |
|
|
183
|
+
|
|
184
|
+
```python
|
|
185
|
+
from useyona.einvoice import EInvoiceApiError, EInvoiceValidationError
|
|
186
|
+
|
|
187
|
+
try:
|
|
188
|
+
client.invoices.create(params)
|
|
189
|
+
except EInvoiceValidationError as err:
|
|
190
|
+
for e in err.errors:
|
|
191
|
+
print(e.field, e.message)
|
|
192
|
+
except EInvoiceApiError as err:
|
|
193
|
+
print(err.status, err.error_code, err.request_id) # quote request_id to support
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Branch on `error_code`, never on the message. Outside the API: `EInvoiceTimeoutError`,
|
|
197
|
+
`EInvoiceConnectionError`, `EInvoiceConfigError`, `EInvoiceWebhookError`; all extend `EInvoiceError`.
|
|
198
|
+
|
|
199
|
+
## Retries and idempotency
|
|
200
|
+
|
|
201
|
+
```python
|
|
202
|
+
from useyona.einvoice import EInvoice, RetryConfig
|
|
203
|
+
|
|
204
|
+
client = EInvoice(api_key=key, timeout=30, retry=RetryConfig(max_retries=3, base_delay=0.5, max_delay=8, max_retry_after=30))
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
The SDK retries GET, PUT and DELETE, and writes that carry an `Idempotency-Key`, on network errors,
|
|
208
|
+
timeouts, 408, 429 and 5xx, with exponential backoff and jitter; a `Retry-After` on 429/503 is
|
|
209
|
+
waited out up to `max_retry_after` seconds (a longer one is raised at once, with `retry_after` set).
|
|
210
|
+
Other writes are never retried for you. `timeout` (seconds) bounds each attempt, headers and body.
|
|
211
|
+
|
|
212
|
+
On routes that accept an `Idempotency-Key` (`invoices.create`, `submissions.submit`, `output.send`,
|
|
213
|
+
the downloads…) the SDK generates one per call, so its own retries are never applied or charged
|
|
214
|
+
twice. Pass your own to make a retry across process restarts safe:
|
|
215
|
+
|
|
216
|
+
```python
|
|
217
|
+
from useyona.einvoice import RequestOptions
|
|
218
|
+
|
|
219
|
+
client.invoices.create(params, RequestOptions(idempotency_key=f"order-{order_id}"))
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
`RequestOptions` also takes `timeout`, `headers` and `max_retries` for one call.
|
|
223
|
+
|
|
224
|
+
## Webhooks
|
|
225
|
+
|
|
226
|
+
```python
|
|
227
|
+
from useyona.einvoice.webhooks import verify_webhook
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
@app.post("/webhooks/yona")
|
|
231
|
+
def yona_webhook():
|
|
232
|
+
event = verify_webhook(request.get_data(), request.headers, os.environ["YONA_WEBHOOK_SECRET"])
|
|
233
|
+
if event["type"] == "invoice.accepted":
|
|
234
|
+
...
|
|
235
|
+
return "", 200
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
Yona signs `t + "." + raw body` with HMAC-SHA256 and sends `Yona-Signature: t=…,v1=…` (a second
|
|
239
|
+
`v1=` while a rotated secret overlaps). `verify_webhook` accepts the delivery when a signature
|
|
240
|
+
matches in constant time and `t` is within ±300 s, and returns the parsed event. Pass the raw body
|
|
241
|
+
bytes, never a re-serialised object. Deduplicate on `event["id"]`. `sign_webhook_payload` signs a
|
|
242
|
+
payload exactly as Yona does, for testing your handler. Endpoints are registered in the dashboard;
|
|
243
|
+
the key can list and test them (`client.webhooks.endpoints`), read deliveries and redeliver.
|
|
244
|
+
|
|
245
|
+
## What an API key cannot do
|
|
246
|
+
|
|
247
|
+
Users, invitations, roles, API keys, organisation management, collections, purchases and webhook
|
|
248
|
+
endpoint writes are done by a signed-in user in the dashboard; the API answers 403 `AUTH018` to a
|
|
249
|
+
key. The seller is the organisation itself (read-only; `sellers.create/update/delete` are 409
|
|
250
|
+
`BIZ205` and have no method). `EXCLUDED_OPERATIONS` lists the API-key operations the SDK deliberately
|
|
251
|
+
has no method for, with the reason.
|
|
252
|
+
|
|
253
|
+
## API reference
|
|
254
|
+
|
|
255
|
+
Every method takes an optional trailing `options: RequestOptions`. Query and body parameters are
|
|
256
|
+
`TypedDict`s named after the operation (`ListInvoicesQuery`, `CreateInvoiceBody`), all in
|
|
257
|
+
`useyona.einvoice.types`.
|
|
258
|
+
|
|
259
|
+
#### `client.invoices`
|
|
260
|
+
`create(params)`, `list(query)`, `get(id)`, `update(id, params)`, `delete(id)`, `finalise(id)`, `reopen(id)`, `revise(id)`, `cancel(id, params)`, `issue_credit_note(id, params)`, `issue_debit_note(id, params)`, `get_overview(query)`, `get_statistics(query)`, `get_summary(query)`
|
|
261
|
+
|
|
262
|
+
#### `client.submissions`
|
|
263
|
+
`submit(id, query)`, `issue(id)`, `create_and_submit(params)`, `batch_submit(params)`, `retry(id)`, `renumber(id)`, `query_status(id)`, `get_status(id)`, `record_payment(id, params)`, `get_authority_copy(id)`
|
|
264
|
+
|
|
265
|
+
#### `client.output`
|
|
266
|
+
`get_download_link(id)`, `download_pdf(id)` → `BinaryResponse`, `send(id, params)`
|
|
267
|
+
|
|
268
|
+
#### `client.share_links`
|
|
269
|
+
`create(invoice_id, params)`, `list(invoice_id)`, `revoke(invoice_id, link_id)`
|
|
270
|
+
|
|
271
|
+
#### `client.items`
|
|
272
|
+
`list(query)`, `create(params)`, `get(id)`, `update(id, params)`, `delete(id)`, `archive(id)`, `unarchive(id)`, `list_used_codes(query)`
|
|
273
|
+
|
|
274
|
+
#### `client.reference`
|
|
275
|
+
`list_hs_codes(query)`, `list_hs_code_categories()`, `list_resources()`, `get_resource(type)`, `lookup_tax_id(value, query)`, `validate_invoice(params)`
|
|
276
|
+
|
|
277
|
+
#### `client.buyers`
|
|
278
|
+
`create(params)`, `list(query)`, `get(id)`, `update(id, params)`, `delete(id)`, `bulk_delete(params)`, `verify_tax_number(id)`, `get_verification_status(id)`, `search(query)`, `check_reachability(query)`, `check_with_tax_authority(params)`
|
|
279
|
+
|
|
280
|
+
#### `client.sellers`
|
|
281
|
+
`list(query)`, `get(id)`, `get_verification_status(id)`, `search(query)`
|
|
282
|
+
|
|
283
|
+
#### `client.inbound_invoices`
|
|
284
|
+
`list(query)` → `Paginated`, `get(id)`, `get_analytics(query)`, `list_history_runs(query)` → `Paginated`, `get_history_run(run_id)`, `load_older()` (deprecated)
|
|
285
|
+
|
|
286
|
+
#### `client.issued_history`
|
|
287
|
+
`list(query)` → `Paginated`, `get(id)`, `download_pdf(id)` → `BinaryResponse`
|
|
288
|
+
|
|
289
|
+
#### `client.invoice_settings` · `client.tax_connection`
|
|
290
|
+
`get()`
|
|
291
|
+
|
|
292
|
+
#### `client.organization`
|
|
293
|
+
`get(org_id)`, `get_readiness()`
|
|
294
|
+
|
|
295
|
+
#### `client.billing.accounts`
|
|
296
|
+
`get_mine(query)`, `get_stats(account_id="me", query)`, `check_balance(account_id, query)`
|
|
297
|
+
|
|
298
|
+
#### `client.billing.payments`
|
|
299
|
+
`list(query)`, `get(id)`
|
|
300
|
+
|
|
301
|
+
#### `client.billing.sandbox`
|
|
302
|
+
`list_transactions(query)`, `get_usage()`
|
|
303
|
+
|
|
304
|
+
#### `client.billing.statements`
|
|
305
|
+
`get(period, query)`
|
|
306
|
+
|
|
307
|
+
#### `client.billing.subscriptions`
|
|
308
|
+
`get_active()`, `list(query)`, `get(id)`, `list_renewals(query)`, `preview_plan_change(id, query)`
|
|
309
|
+
|
|
310
|
+
#### `client.billing.transactions`
|
|
311
|
+
`list(query)`, `get(id)`, `get_usage_analytics(query)`, `get_usage_by_cost_code(query)`
|
|
312
|
+
|
|
313
|
+
#### `client.webhooks.endpoints`
|
|
314
|
+
`list()`, `get(id)`, `test(id, params=None)`
|
|
315
|
+
|
|
316
|
+
#### `client.webhooks.deliveries`
|
|
317
|
+
`list(query)`, `get(id)`, `redeliver(id)`
|
|
318
|
+
|
|
319
|
+
#### `client.webhooks.events`
|
|
320
|
+
`list(query)`, `get(id)`, `redeliver(id, params)`
|
|
321
|
+
|
|
322
|
+
#### `client.webhooks.event_types`
|
|
323
|
+
`list()`
|
|
324
|
+
|
|
325
|
+
#### `useyona.einvoice.webhooks`
|
|
326
|
+
`verify_webhook(payload, headers, secret, *, tolerance_seconds=300, now=None)`, `sign_webhook_payload(payload, secrets, timestamp=None)`, `compute_webhook_signature(payload, secret, timestamp)`, `parse_signature_header(header)`
|
|
327
|
+
|
|
328
|
+
## Advanced: `base_url`
|
|
329
|
+
|
|
330
|
+
`base_url` points the client at another gateway (a local one in development). It never changes
|
|
331
|
+
the mode: the key does. Never switch hosts by mode in your own code.
|
|
332
|
+
|
|
333
|
+
## Development
|
|
334
|
+
|
|
335
|
+
```bash
|
|
336
|
+
make install # a venv is recommended: python3 -m venv .venv && . .venv/bin/activate
|
|
337
|
+
make test # pytest with coverage, parity included
|
|
338
|
+
make lint # ruff + mypy --strict
|
|
339
|
+
make sync # copy the snapshot and vectors from einvoice-js and regenerate the models (needs Node 22)
|
|
340
|
+
make sync-check # CI: the three must match the pinned einvoice-js commit
|
|
341
|
+
make guides # examples/ → guides/guides.json (a test fails when it is stale)
|
|
342
|
+
make examples # run the examples (YONA_API_KEY; YONA_BASE_URL to point elsewhere)
|
|
343
|
+
make smoke-remote # verify your own sandbox key (see "Verifying your setup")
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
The models (`useyona/einvoice/types/generated.py`), the API snapshot and the webhook test vectors come
|
|
347
|
+
from [`einvoice-js`](https://github.com/Elyonar/einvoice-js), the source of truth for every Yona SDK;
|
|
348
|
+
`tests/test_parity.py` fails when a method and the snapshot disagree.
|
|
349
|
+
|
|
350
|
+
## License
|
|
351
|
+
|
|
352
|
+
MIT
|