Skip to main content

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:

  • DIGITAL encrypts a recipient-specific envelope with AES-256-GCM and wraps its key with RSA-OAEP SHA-256.
  • DOWNLOAD_FALLBACK creates 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_email is available, the CHEQI receipt is sent through /receipt/email.
  • A found route without deliveryRouteType is 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

cheqi_sdk-0.2.1.tar.gz (90.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cheqi_sdk-0.2.1-py3-none-any.whl (173.2 kB view details)

Uploaded Python 3

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

Hashes for cheqi_sdk-0.2.1.tar.gz
Algorithm Hash digest
SHA256 7fd95839ed2c8eb5e9f671b35b1363fba173b9c2892641a87670f498bccc9335
MD5 20207e91c7874d4c62a08c0b2e1dfe4c
BLAKE2b-256 8fefb3b450177603596a0a3d970c766155ce2bca3b87daed098b6f5a38a32e19

See more details on using hashes here.

Provenance

The following attestation bundles were made for cheqi_sdk-0.2.1.tar.gz:

Publisher: publish.yml on cheqi-io/cheqi-sdk-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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

Hashes for cheqi_sdk-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 28b19108c16ca7ef7c219807ff186d3d2304418ae9339595aed788c41ac053fd
MD5 0c542e4dec917c9fed3b867efaa3bdd2
BLAKE2b-256 916cb352663b36f9602fd4edbf0339720509639d1ee0f63ee1ddbed53ead9a26

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page