{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":[]},"type":"markdown"},"seo":{"title":"Download links","description":"Complete documentation for integrating Cheqi's digital receipt platform","keywords":["cheqi","digital receipts","api","sdk","java","javascript"],"llmstxt":{"hide":false,"sections":[{"title":"Table of contents","includeFiles":["**/*"],"excludeFiles":[]}],"excludeFiles":[]}},"dynamicMarkdocComponents":[],"compilationErrors":[],"ast":{"$$mdtype":"Tag","name":"article","attributes":{},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":1,"id":"download-links","__idx":0},"children":["Download links"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Cheqi download links give a customer a hosted receipt URL when no wallet recipient is available. The same client-encrypted mechanism is used for an online download fallback and for a URL issued while the Cheqi API is temporarily unavailable."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"text","header":{"controls":{"copy":{}}},"source":"https://receipt.cheqi.io/{downloadId}#{contentKey}\n","lang":"text"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The SDK generates the download ID and AES-256-GCM content key locally. It builds"," ","the canonical download envelope locally, encrypts it, and uploads only"," ","ciphertext through ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["POST /receipt/download"]},". The fragment after ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["#"]}," is not sent"," ","to Cheqi by the browser, so Cheqi cannot decrypt the receipt. Decryption happens"," ","in the customer's browser."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Use ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["https://receipt.cheqi.io"]}," in production and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["https://sandbox.receipt.cheqi.io"]}," in sandbox."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"online-fallback","__idx":1},"children":["Online fallback"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Download fallback is enabled for the company or client application. When recipient resolution cannot find a wallet recipient and selects ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["DOWNLOAD_FALLBACK"]},", the SDK:"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["generates the download URL and fragment key locally"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["builds the canonical download envelope from the definitive receipt input"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["encrypts that envelope locally"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["uploads the ciphertext through ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["POST /receipt/download"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["returns the download URL to your integration"]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Your integration can render the URL as a QR code, print it, include it in an order confirmation, or show it on an order-status page."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["When the API is reachable and recipient resolution returns ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["routeFound: false"]},", stop with customer-not-found. Do not call the low-level upload endpoint to bypass a disabled download fallback."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"service-outage","__idx":2},"children":["Service outage"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The URL can also be generated without a network call. This lets a POS display or print the QR code while Cheqi is unavailable. The receipt page tells the customer that the receipt is not ready yet and asks them to return later."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Before exposing the URL, your integration must durably store:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["the download URL or its download ID and content key"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["the original definitive receipt input and requested formats"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["issuer and jurisdiction context required for local generation"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["a stable merchant transaction identifier"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["the current processing state and operational timestamps"]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["When Cheqi is reachable again, your processing builds and encrypts the canonical"," ","download envelope with the SDK, persists the ciphertext, and uploads it. Do not"," ","implement a separate offline receipt renderer or envelope format."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["An already issued outage URL may be completed even if a later recipient resolution produces no route. ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["POST /receipt/download"]}," deliberately takes no ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["matchId"]}," and does not re-evaluate the fallback setting, because the customer already possesses the URL."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"retry-contract","__idx":3},"children":["Retry contract"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Your integration owns storage, retry scheduling, compute allocation, monitoring, retention, and manual recovery. Cheqi SDKs provide stateless primitives and return values; they do not include a database, outbox, background worker, or extensive retry policy."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Use these states:"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"State"},"children":["State"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Stored data"},"children":["Stored data"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Next action"},"children":["Next action"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["PENDING_DOWNLOAD_TEMPLATE"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["URL credentials and original receipt input"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Retry local envelope generation"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["PENDING_DOWNLOAD_UPLOAD"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["URL credentials, template hash, and exact ciphertext"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Retry the exact stored upload bytes"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["DELIVERED_DOWNLOAD"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Delivery result and URL reference"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["No further submission"]}]}]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Persist ciphertext before attempting upload. If the upload result is ambiguous, retry the exact bytes. AES-GCM uses a random IV, so encrypting again produces different ciphertext."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The first successful write wins permanently. Replaying identical bytes as the same principal is idempotent. Different bytes or a different principal for the same download ID return HTTP 409 and never replace the stored receipt."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Never log the complete URL or fragment key. Anyone with the fragment key can decrypt the receipt."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"java-sdk","__idx":4},"children":["Java SDK"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["For a custom local environment:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"java","header":{"controls":{"copy":{}}},"source":"CheqiSDK sdk = CheqiSDK.builder()\n    .customApiEndpoint(\"http://localhost:8080\")\n    .receiptDownloadBaseUrl(\"http://localhost:5190\")\n    .apiKey(System.getenv(\"CHEQI_API_KEY\"))\n    .maxRetries(0)\n    .build();\n","lang":"java"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The high-level flow completes a client-encrypted download immediately when the"," ","identification details provide enough local payment context:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"java","header":{"controls":{"copy":{}}},"source":"ReceiptResult result = sdk.getReceiptService()\n    .issueReceipt(identificationDetails, receiptPayload);\n\nif (result.isAccepted() && result.getDownloadUrl() != null) {\n    presentToCustomer(result.getDownloadUrl());\n} else if (result.isDownloadEnvelopeRequired()) {\n    ReceiptResult completed = sdk.getReceiptService().completeDownloadFallback(\n        result,\n        receiptEnvelope,\n        templateHash,\n        accessToken\n    );\n    presentToCustomer(completed.getDownloadUrl());\n}\n","lang":"java"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["For an explicit cash or anonymous download flow, use ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["issueDownloadReceipt(...)"]}," ","instead of recipient matching. The content key remains only in the returned URL"," ","fragment."]}]},"headings":[{"value":"Download links","id":"download-links","depth":1},{"value":"Online fallback","id":"online-fallback","depth":2},{"value":"Service outage","id":"service-outage","depth":2},{"value":"Retry contract","id":"retry-contract","depth":2},{"value":"Java SDK","id":"java-sdk","depth":2}],"frontmatter":{"title":"Download Links","description":"Give customers a zero-knowledge receipt URL online or while the Cheqi API is unavailable","seo":{"title":"Download links"}},"lastModified":"2026-08-05T15:06:40.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/receipts/download-fallback","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}