Cheqi Python SDK for end-to-end encrypted receipt processing
Project description
Cheqi Python SDK
Python SDK for issuing end-to-end encrypted Cheqi receipts, encrypted credit notes, email delivery, client-encrypted download fallback, receipt decryption/merge, and store management.
Installation
pip install cheqi-sdk
Or with uv:
uv add cheqi-sdk
Quick Start
from cheqi import CheqiSDK, Environment
from cheqi.models import (
IdentificationDetails,
CardDetails,
ReceiptTemplateRequest,
DeliveryStatus,
NotificationDisplayCode,
Product,
Tax,
UnitCode,
BarcodeType,
PaymentType,
CardProvider,
)
from decimal import Decimal
# Initialize the SDK
sdk = CheqiSDK(
environment=Environment.PRODUCTION,
api_key="sk_live_...",
)
# Build identification details
identification = IdentificationDetails(
payment_type=PaymentType.CARD_PAYMENT,
card_details=CardDetails(
payment_account_reference="PAR123456",
card_provider=CardProvider.VISA,
),
)
# Build a receipt request
product = Product(
name="Laptop",
identifier="LAP-001",
quantity=1.0,
base_quantity=1.0,
unit_code=UnitCode.ONE,
unit_price=Decimal("1000.00"),
subtotal=Decimal("1000.00"),
total=Decimal("1210.00"),
taxes=[Tax(rate=21.0, type="VAT", taxable_amount=Decimal("1000.00"), amount=Decimal("210.00"))],
)
receipt_request = ReceiptTemplateRequest(
document_number="INV-2024-001",
currency="EUR",
receipt_subtotal=Decimal("1000.00"),
total_before_tax=Decimal("1000.00"),
total_tax_amount=Decimal("210.00"),
total_amount=Decimal("1210.00"),
products=[product],
taxes=[Tax(rate=21.0, type="VAT", taxable_amount=Decimal("1000.00"), amount=Decimal("210.00"))],
)
# Process the complete receipt (match -> template -> encrypt -> send)
result = sdk.receipt_service.process_complete_receipt(
identification_details=identification,
receipt_request=receipt_request,
)
if result.success:
print(f"Receipt route: {result.delivery_status}")
print(f"Receipt ID: {result.cheqi_receipt_id}")
The high-level flow now follows the same route contract as the Java SDK:
DIGITALencrypts a recipient-specific envelope with AES-256-GCM and wraps its key with RSA-OAEP SHA-256.DOWNLOAD_FALLBACKcreates a QR URL locally, encrypts the complete envelope with the fragment key, and uploads only ciphertext to/receipt/download.- If no route is found and
recipient_emailis available, the CHEQI receipt is sent through/receipt/email. - A found route without
deliveryRouteTypeis rejected to avoid accidentally using the retired server-held fallback-key flow.
VAT Context and Formats
Recipient resolution supplies buyer_country_code and buyer_type; the high-level flow adds them to template generation unless the receipt request overrides them. If taxes_applied is omitted, the SDK infers it from a positive total tax amount or a non-empty receipt tax list.
The supported recipient formats are CHEQI, UBL_PURCHASE_RECEIPT, UBL_INVOICE, and UBL_CREDIT_NOTE. Each digital recipient receives only the formats it declared.
Notification Display Code
If the merchant has notification-code rendering enabled, you can attach a QR code or barcode to the high-level receipt flow. The code is sent as request metadata and rendered by supported mobile clients directly from the push notification.
notification_display_code = NotificationDisplayCode(
type=BarcodeType.QR_CODE,
data="https://example.com/receipt/INV-2024-001",
)
result = sdk.receipt_service.process_complete_receipt(
identification_details=identification,
receipt_request=receipt_request,
notification_display_code=notification_display_code,
)
If the merchant is not enabled for this feature, or you omit notification_display_code, the normal receipt push is sent.
Client-Encrypted Download Fallback
Standard environments automatically map to the customer-facing origins https://receipt.cheqi.io and https://sandbox.receipt.cheqi.io. For a custom API endpoint, configure the receipt origin explicitly:
sdk = CheqiSDK(
custom_api_endpoint="http://localhost:8080",
receipt_download_base_url="http://localhost:3000/receipt",
api_key="sk_test_...",
)
process_complete_receipt handles a DOWNLOAD_FALLBACK response automatically. The AES-256 key exists only in the URL fragment, so it is never sent to Cheqi:
result = sdk.receipt_service.process_complete_receipt(identification, receipt_request)
if result.delivery_status == DeliveryStatus.DELIVERED_DOWNLOAD:
render_qr(result.download_url)
You can also create the URL before any network call and own persistence/scheduling yourself:
from cheqi.models import ClientReceiptDownloadRequest, ReceiptFormat
link = sdk.download_service.generate_download_link(Environment.PRODUCTION)
persist_link_credentials(link.download_id, link.content_key)
render_qr(link.url)
# Later, after obtaining the normal server-generated template:
template = sdk.receipt_service.generate_receipt_template(
receipt_request,
[ReceiptFormat.CHEQI],
)
envelope = sdk.download_service.build_download_envelope(template)
ciphertext = sdk.download_service.encrypt_download_envelope(envelope, link.content_key)
# Persist these exact bytes before uploading. A retry must reuse the ciphertext;
# encrypting again generates a new GCM IV.
persist_ciphertext(link.download_id, ciphertext)
response = sdk.receipt_service.upload_client_encrypted_receipt(
ClientReceiptDownloadRequest(
download_id=link.download_id,
ciphertext=ciphertext,
)
)
Transient matching/template failures return PENDING_DOWNLOAD_TEMPLATE with a usable URL. A transient upload failure returns PENDING_DOWNLOAD_UPLOAD with download_ciphertext, template_hash, and the same URL so the integration can safely resume. The SDK deliberately does not create background workers or store pending jobs.
Receipt Decryption and Context Merge
Queued encrypted receipts can contain a separately encrypted customer-context envelope. The SDK decrypts both payloads and merges receiving-party and payment-means data into CHEQI JSON, UBL PurchaseReceipt, and UBL Invoice representations:
decrypted = sdk.process_encrypted_receipt(encrypted_receipt, private_key)
complete_envelope = decrypted.receipt_envelope
Raw decrypted strings remain available as decrypted.receipt_content and decrypted.customer_details for backward compatibility.
Chainable Model Building
Models are immutable. Convenience methods return new instances:
request = (
ReceiptTemplateRequest(document_number="INV-001", currency="EUR")
.add_product(product1)
.add_product(product2)
.add_tax(tax1)
.add_discount(discount1)
)
Authentication
sdk = CheqiSDK(
environment=Environment.PRODUCTION,
api_key="sk_live_...",
)
Development
uv sync --extra dev
uv run pytest
uv run ruff check src/ tests/
uv run mypy src/
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cheqi_sdk-0.2.1.tar.gz.
File metadata
- Download URL: cheqi_sdk-0.2.1.tar.gz
- Upload date:
- Size: 90.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7fd95839ed2c8eb5e9f671b35b1363fba173b9c2892641a87670f498bccc9335
|
|
| MD5 |
20207e91c7874d4c62a08c0b2e1dfe4c
|
|
| BLAKE2b-256 |
8fefb3b450177603596a0a3d970c766155ce2bca3b87daed098b6f5a38a32e19
|
Provenance
The following attestation bundles were made for cheqi_sdk-0.2.1.tar.gz:
Publisher:
publish.yml on cheqi-io/cheqi-sdk-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cheqi_sdk-0.2.1.tar.gz -
Subject digest:
7fd95839ed2c8eb5e9f671b35b1363fba173b9c2892641a87670f498bccc9335 - Sigstore transparency entry: 2218144299
- Sigstore integration time:
-
Permalink:
cheqi-io/cheqi-sdk-python@ecfc1128f7c3b5868cc6f7b12e38c909db0229f3 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/cheqi-io
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@ecfc1128f7c3b5868cc6f7b12e38c909db0229f3 -
Trigger Event:
push
-
Statement type:
File details
Details for the file cheqi_sdk-0.2.1-py3-none-any.whl.
File metadata
- Download URL: cheqi_sdk-0.2.1-py3-none-any.whl
- Upload date:
- Size: 173.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
28b19108c16ca7ef7c219807ff186d3d2304418ae9339595aed788c41ac053fd
|
|
| MD5 |
0c542e4dec917c9fed3b867efaa3bdd2
|
|
| BLAKE2b-256 |
916cb352663b36f9602fd4edbf0339720509639d1ee0f63ee1ddbed53ead9a26
|
Provenance
The following attestation bundles were made for cheqi_sdk-0.2.1-py3-none-any.whl:
Publisher:
publish.yml on cheqi-io/cheqi-sdk-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cheqi_sdk-0.2.1-py3-none-any.whl -
Subject digest:
28b19108c16ca7ef7c219807ff186d3d2304418ae9339595aed788c41ac053fd - Sigstore transparency entry: 2218144327
- Sigstore integration time:
-
Permalink:
cheqi-io/cheqi-sdk-python@ecfc1128f7c3b5868cc6f7b12e38c909db0229f3 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/cheqi-io
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@ecfc1128f7c3b5868cc6f7b12e38c909db0229f3 -
Trigger Event:
push
-
Statement type: