Metadata-Version: 2.4
Name: nordinvoice
Version: 0.1.1
Summary: Official Python SDK for the NordInvoice API: validate, generate and deliver Peppol e-invoices from your own product.
Author-email: NordInvoice <hello@nordinvoice.com>
License: MIT
Project-URL: Homepage, https://nordinvoice.com
Project-URL: Documentation, https://docs.nordinvoice.com
Project-URL: Repository, https://github.com/nordinvoice/nordinvoice-python
Keywords: peppol,e-invoicing,ubl,xrechnung,nlcius,en16931,invoice,nordinvoice
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Office/Business :: Financial :: Accounting
Classifier: Typing :: Typed
Requires-Python: >=3.9
Description-Content-Type: text/markdown

# nordinvoice

Official Python SDK for the [NordInvoice](https://nordinvoice.com) API: validate, generate and deliver Peppol e-invoices from your own product. No UBL. No Schematron. No compliance team.

- Zero dependencies; Python 3.9+
- Typed errors (`RateLimitedError`, `PaymentRequiredError`, …) with the API's machine-readable codes
- Automatic retry on rate limits, honouring `Retry-After`
- Fully type-hinted (`py.typed`)

## Install

```bash
pip install nordinvoice
```

## Your first invoice in five minutes

Get a free sandbox key at [nordinvoice.com/register](https://nordinvoice.com/register) — the dashboard creates a working `nord_test_` key in seconds.

```python
from nordinvoice import NordInvoice

nord = NordInvoice(api_key="nord_test_...")

result = nord.invoices.create({
    "invoiceNumber": "INV-2026-001",
    "issueDate": "2026-08-06",
    "dueDate": "2026-09-05",
    "currency": "EUR",
    "buyerReference": "PO-2026-001",
    "seller": {
        "name": "Demo Supplier BV", "street": "Keizersgracht 1", "city": "Amsterdam",
        "postalCode": "1015 CC", "countryCode": "NL", "vatNumber": "NL123456789B01",
        "electronicAddress": "12345678", "electronicAddressScheme": "0106",
    },
    "buyer": {
        "name": "Demo Buyer GmbH", "street": "Unter den Linden 5", "city": "Berlin",
        "postalCode": "10117", "countryCode": "DE", "vatNumber": "DE123456789",
        "electronicAddress": "991234567", "electronicAddressScheme": "0204",
    },
    "paymentIban": "NL91ABNA0417164300",
    "lines": [{"description": "Consultancy", "quantity": 10, "unitCode": "C62",
               "unitPrice": 100, "vatPercent": 21}],
}, send=True)

print(result["readyToSend"])        # True: the draft passed the full rule set
print(result["job"]["id"])          # delivery queued; poll nord.jobs.get(id)
```

Sandbox keys deliver to a simulated network, so you can integrate end to end before anything real leaves the building.

## What else it does

```python
# Validate your own UBL/CII XML (or a ZUGFeRD PDF) against any of 11 rule sets
outcome = nord.validate.file(xml, "invoice.xml", "xrechnung-invoice")

# Generate UBL without sending or charging — credit notes included
cn = nord.generate(draft, "peppol-creditnote")

# Bulk delivery: up to 25 files per call
job = nord.jobs.send([("a.xml", xml_a), ("b.xml", xml_b)])

# Sending history, filterable and paged
rows = nord.shipments.list(status="DELIVERED", month="2026-08")

# Is my customer on Peppol?
check = nord.participants.verify("0106:12345678")

# EU VAT number check against VIES
vat = nord.vat("NL", "123456789B01")

# Receiving: register once, then read your inbox
nord.receiving.register({"name": "...", "address": "...", "postalCode": "...",
                         "city": "...", "country": "NL"})
inbox = nord.receiving.inbox()

# Signed webhooks for delivery events
hook = nord.webhooks.create("https://your-app.example/webhooks/nordinvoice")
```

## Errors

Every non-2xx answer raises a typed exception carrying the HTTP status and the API's error code:

```python
from nordinvoice import PaymentRequiredError, RateLimitedError

try:
    nord.invoices.create(draft, send=True)
except PaymentRequiredError:
    ...  # monthly quota exhausted, or live sending needs a subscription/credits
except RateLimitedError as error:
    print("retry in", error.retry_after_seconds, "s")
```

Rate-limited requests are retried automatically (twice by default, waiting out `Retry-After`); tune with `max_retries`.

## Options

```python
NordInvoice(
    api_key="nord_live_...",             # required
    base_url="https://nordinvoice.com",  # default
    language="de",                       # error messages in en, de or nl
    timeout=60.0,
    max_retries=2,
)
```

## Documentation

Full API reference and a live console for every endpoint: [docs.nordinvoice.com](https://docs.nordinvoice.com)

## License

MIT
