Skip to Content
SDKsPython

Python

useyona-einvoice is the official SDK for Python 3.10 and later. It is fully typed: every request and response dictionary has a TypedDict with the API’s field names, so your editor and type checker know the shape of what you send and receive.

Install

pip install useyona-einvoice

Quick start

You need a sandbox key

Create one in the Yona app under API keys, with the invoicing preset; it starts with sk_test_. The SDK needs nothing else: no host and no environment setting, because the key chooses the sandbox or the live service.

import os from useyona.einvoice import EInvoice client = EInvoice(api_key=os.environ["YONA_API_KEY"]) # 1. A buyer buyer = client.buyers.create({ "name": "Acme Nigeria Ltd", "taxId": "12345678-0001", "email": "accounts@acme.ng", "partyType": "company", "address": {"line1": "1 Marina", "city": "Lagos", "country": "NG"}, }) # 2. A saved item item = client.items.create({ "name": "Laptop", "itemType": "goods", "hsnCode": "8471.30", "productCategory": "Machinery", "unitCode": "EA", "unitPriceMinor": "45000000", "currency": "NGN", "taxCategory": "STANDARD_VAT", }) # 3. A draft invoice invoice = client.invoices.create({ "invoiceKind": "B2B", "invoiceDate": "2026-10-05", "currency": "NGN", "buyerId": buyer["id"], "lineItems": [{"itemId": item["id"], "quantity": 2}], }) # 4. Finalise it and report it to the tax authority client.invoices.finalise(invoice["id"]) client.submissions.submit(invoice["id"]) status = client.submissions.get_status(invoice["id"])

Submitting is asynchronous: poll submissions.get_status or listen for the invoice.accepted webhook. The states are explained in Invoice lifecycle.

The client holds a connection pool: close it with client.close() or use with EInvoice(...) as client:.

Sandbox and live

An sk_test_ key works in the sandbox and an sk_live_ key in live, on the same host; client.mode tells you which. To make a deployment refuse a key of the wrong kind:

EInvoice(api_key=key, assert_mode="live")

Responses and pagination

Methods return the API’s answer as a typed dictionary with the API’s field names (invoice["invoiceNumber"]). List methods return a page:

page = client.buyers.list({"limit": 50})

page.data holds the buyers and page.pagination carries total, page, pageSize, totalPages, hasNext and hasPrevious.

paginate walks every page for you:

from useyona.einvoice import paginate for buyer in paginate(client.buyers.list, {"limit": 100}): print(buyer["name"])

Received invoices and issued history return a Paginated object with the items under res.data["items"]. PDF downloads return a BinaryResponse with data (bytes), content_type and file_name.

Errors

A refused request raises an exception chosen by status:

StatusException
400, 422EInvoiceValidationError
401EInvoiceAuthenticationError
402EInvoiceInsufficientCreditsError
403EInvoicePermissionError
404EInvoiceNotFoundError
409EInvoiceConflictError
429EInvoiceRateLimitError
5xxEInvoiceServerError

All extend EInvoiceApiError, which carries status, error_code, errors (per field), request_id and retry_after:

from useyona.einvoice import EInvoiceApiError, EInvoiceValidationError try: client.invoices.create(params) except EInvoiceValidationError as err: for e in err.errors: print(e.field, e.message) except EInvoiceApiError as err: print(err.status, err.error_code, err.request_id)

Branch on error_code, not on the message, and quote request_id when you write to support. Problems before the API answers are EInvoiceTimeoutError, EInvoiceConnectionError and EInvoiceConfigError; all SDK errors extend EInvoiceError. The codes are listed on each page of the API Reference.

Retries and idempotency

Reads, and writes that carry an Idempotency-Key, are retried automatically on network errors, timeouts, 408, 429 and 5xx, with backoff and respecting Retry-After. Other writes are never retried.

Where the API accepts an Idempotency-Key (creating an invoice, submitting, sending, downloading and so on) the SDK generates one per call, so a retry is never applied or charged twice. Pass your own to make a retry safe across restarts:

from useyona.einvoice import RequestOptions client.invoices.create(params, RequestOptions(idempotency_key=f"order-{order_id}"))

Tune the defaults with timeout and retry=RetryConfig(...) when creating the client, or per call with RequestOptions (timeout, headers, max_retries).

Webhooks

from useyona.einvoice.webhooks import verify_webhook @app.post("/webhooks/yona") def yona_webhook(): secret = os.environ["YONA_WEBHOOK_SECRET"] event = verify_webhook(request.get_data(), request.headers, secret) if event["type"] == "invoice.accepted": ... return "", 200

verify_webhook checks the Yona-Signature header over the raw body, accepts either signature while a rotated secret overlaps, and returns the event; a failed check raises EInvoiceWebhookError. Always pass the raw bytes, and deduplicate on event["id"]. sign_webhook_payload signs a payload the way Yona does, so you can test your handler locally.

Endpoints are created and their secrets rotated in the Yona app; the SDK can list and test endpoints and read and redeliver deliveries and events. See Webhooks for the events.

Configuration

EInvoice(api_key, ...) accepts:

OptionPurpose
assert_mode"sandbox" or "live": refuse a key of the other kind
timeoutper-attempt timeout in seconds (default 30)
retry=RetryConfig(...)max_retries (2), base_delay (0.5 s), max_delay (8 s), max_retry_after (60 s)
headersheaders sent on every request
http_clientyour own httpx.Client (proxy, TLS)
base_urlanother gateway, for local development only; the key decides sandbox or live

What it covers

Every module mirrors a tag of the API Reference, and the method names are the reference’s operation names in the casing of the language (issue_credit_note, get_status). Every method takes an optional trailing options: RequestOptions; request and query dictionaries are typed after the operation (CreateInvoiceBody, ListInvoicesQuery) in useyona.einvoice.types. Each method needs the capability shown on the key; the full_integration preset has them all.

ModuleWhat it doesReference
client.invoices, client.submissions, client.output, client.share_linksCreate, edit and finalise drafts; submit, retry and track them; credit and debit notes; PDFs, sending and share linksInvoices
client.buyersThe businesses and people you invoice, with tax-number checks and reachabilityBuyers
client.itemsWhat you sell, with codes, units, prices and tax categoriesItems
client.referenceHS codes, reference lists, tax-ID lookup and invoice validationReference data
client.sellersYour organisation as the seller, read-onlySellers
client.inbound_invoices, client.issued_historyInvoices other businesses sent you, and your issued history retrieved from the authorityReceived invoices
client.organization, client.invoice_settings, client.tax_connectionYour organisation and its readiness, invoice settings, the tax connectionOrganizations, Tax connection
client.billingCredits and usage, payments, statements and your subscription, in accounts, payments, sandbox, statements, subscriptions, transactionsBilling
client.webhooksList and test endpoints; read and redeliver deliveries and events, in endpoints, deliveries, events, event_typesWebhooks

Account management (users, roles, API keys, purchases, webhook endpoint settings) is done in the Yona app, not through the API key.

Next steps

  • Invoice lifecycle: the states a submission climbs through, and what each one means
  • Webhooks: the events, and how deliveries are retried
  • Going live: the checklist before you deploy a live key
  • API Reference: every field, status code and error code