Skip to main content

Konfidant Python SDK

Test Codacy Badge Codacy Badge

Python SDK for the Konfidant API. Share text and files through single-use, time-limited links that are encrypted on your machine before anything is sent.

Zero-knowledge model

  • Every share gets a fresh random 256-bit key. Content is encrypted locally with AES-256-GCM in the KNF1 format (chunked, authenticated, truncation-resistant).

  • Konfidant receives only ciphertext. The file name and MIME type are encrypted too; the server learns only the ciphertext size and when the share was created and opened.

  • The key lives only in the share link's URL fragment:

    https://download.konfidant.app/#t=<single-use token>&k=<key>
    

    Browsers and HTTP clients never send the fragment to a server. The t token lets the recipient fetch the ciphertext exactly once; the k key decrypts it locally.

  • Treat the share URL as the secret. Do not log it, and send it to the recipient over a channel you trust. If the link is lost, the content cannot be recovered: Konfidant does not have the key.

Requirements

Installation

pip install konfidant

Quick start

from konfidant import KonfidantClient

with KonfidantClient(api_key="your-api-key") as client:
    result = client.share_text("Secret message", ttl_hours=24)
    print(result.share_url)  # https://download.konfidant.app/#t=...&k=...

Configuration

client = KonfidantClient(
    api_key="your-api-key",                # sent as "Authorization: Bearer <api_key>" to the Konfidant API only
    base_url="https://www.konfidant.app",  # default
    timeout=120.0,                         # seconds; None disables the timeout
)

Usage

Share text

result = client.share_text("Secret message", ttl_hours=24)

result.share_url   # "https://download.konfidant.app/#t=...&k=..."
result.text_id     # "9140b841-..." or None
result.expires_at  # "2026-10-04T12:00:00.000Z"
Parameter Type Description
text str The message. Encrypted locally; never sent in plaintext.
ttl_hours int | None How long the link stays valid. None uses the server default.

Share a file

Encrypts locally, uploads the ciphertext and returns the share link in one call.

with open("report.pdf", "rb") as f:
    result = client.share_file(f, filename="report.pdf", content_type="application/pdf", ttl_hours=48)

result.share_url      # "https://download.konfidant.app/#t=...&k=..."
result.file_id        # "681da863-..." or None
result.expires_at     # "2026-10-05T12:00:00.000Z"
result.verified_burn  # True when the organization records burn-on-read confirmation
Parameter Type Default Description
data bytes | BinaryIO — Content, or a binary file object (read from its current position)
filename str — Original file name, at most 1024 UTF-8 bytes. Encrypted.
content_type str "" MIME type, at most 255 bytes. Encrypted.
ttl_hours int | None None How long the link stays valid. None uses the server default.

Seekable files are encrypted and uploaded chunk by chunk (a few MB of memory at a time). Non-seekable streams (pipes, sockets) are read into memory first, because the exact ciphertext size must be declared before the upload. Files larger than your plan's limit are rejected by the API before anything is uploaded.

Share a file step by step

The low-level methods expose each stage, for example to run the upload yourself. Encryption comes from the konfidant.knf module.

from konfidant import knf

content = open("archive.zip", "rb").read()
key = knf.generate_key()
ciphertext = knf.encrypt(key, content, kind="file", name="archive.zip", mime="application/zip")

upload = client.create_file_upload(ciphertext_size=len(ciphertext), ttl_hours=48)
client.upload_ciphertext(upload, ciphertext)          # PUT with exactly upload.upload_headers, no API key
completed = client.complete_file_upload(upload.file_key)

share_url = knf.build_share_url(completed.download_url, key)  # appends "&k=<key>" to "#t=<token>"
  • create_file_upload(ciphertext_size, ttl_hours=None) returns upload_url, file_key, upload_headers and upload_expires_in (seconds). ciphertext_size must be the exact KNF1 length; compute it up front with knf.ciphertext_size(len(knf.encode_metadata("file", name, mime)), content_length).
  • upload_ciphertext(upload, ciphertext, ciphertext_size=None) accepts bytes or an iterable of byte chunks such as knf.encrypt_stream(...) (then ciphertext_size is required). The API key is never sent to the upload URL.
  • complete_file_upload(file_key) returns download_url, file_id, expires_at and verified_burn. It raises KonfidantApiError with status 409 (upload_incomplete) if the upload has not landed.

Open a share (recipient side)

opened = client.open_share("https://download.konfidant.app/#t=...&k=...")

opened.kind  # "text" or "file"
opened.text  # decoded text for text shares, None for files
opened.name  # original file name ("" for text)
opened.mime  # MIME type ("" for text, may be "" for files)
opened.data  # decrypted bytes

open_share posts the token to the link's own origin (download.konfidant.app or a custom domain) and decrypts the response locally. It never sends the API key or the decryption key. Links are single use: the ciphertext is deleted once fetched, and a second attempt raises KonfidantApiError with status 410.

List shares

response = client.list_shares(type="file", status="active", limit=10, offset=0)

for share in response.shares:
    share.type             # "file" or "text"
    share.file_size_bytes  # may be None
    share.created_at
    share.expires_at
    share.accessed_at      # None if not yet opened
    share.created_by       # creator's email, None if the user was deleted

response.pagination.total
response.pagination.has_more

File names are not listed: the server never sees them.

Encryption module

konfidant.knf implements KNF1 and can be used without the client:

Function Description
generate_key() 32 random bytes
encode_key(key) / decode_key(s) Unpadded base64url, 43 characters
encrypt(key, source, kind=, name=, mime=) Bytes or binary file object → KNF1 bytes
encrypt_stream(...) Same, yields header and sealed chunks lazily
encrypt_text(key, text) Text share payload
decrypt(key, ciphertext) → KnfDecrypted(kind, name, mime, data, .text)
Decryptor(key).push(bytes) / .finish() Incremental decryption of streamed downloads
ciphertext_size(meta_len, content_len) Exact KNF1 size
build_share_url(download_url, key) / parse_share_url(url) Share link helpers

Any authentication failure (wrong key, modified, reordered or truncated data) raises knf.KnfError and returns no plaintext.

Error handling

from konfidant import KonfidantApiError, KnfError, KonfidantClient

try:
    result = client.share_text("Secret", ttl_hours=24)
except KonfidantApiError as e:
    e.status_code  # e.g. 401, 409, 410
    str(e)         # the API's "error" code, e.g. "unauthorized"
    e.body         # parsed JSON {"error": ..., "message": ...} or raw text
except KnfError as e:
    ...            # invalid input (e.g. file name too long) or failed decryption

upload_ciphertext raises KonfidantApiError if the storage upload fails.

Development

poetry install --with dev
poetry run pytest --cov=konfidant

tests/knf1-test-vectors.json holds the KNF1 test vectors shared with the web app; the tests reproduce every ciphertext byte for byte.

Metadata

Release files for konfidant 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for konfidant 1.0.0
File Size Uploaded
konfidant-1.0.0.tar.gz 15.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for konfidant 1.0.0
File Interpreter ABI Platform
konfidant-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 29.7 kB

Release files / konfidant-1.0.0.tar.gz

Download URL konfidant-1.0.0.tar.gz
Size 15.1 kB
Tags Source
SHA-256 checksum
How to use checksums
309ab679fc3533417558ad77e4f57dea946b171099d859c607dd7a41820fb568
BLAKE2b-256 checksum
How to use checksums
33b4c77e19ea5fd87c3858ad507af030408711d314dc4647b9bb39e1bc857e5b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 3, 2026.

Transparency log

Release files / konfidant-1.0.0-py3-none-any.whl

Download URL konfidant-1.0.0-py3-none-any.whl
Size 14.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
390c1973ca9bf26c922bea9cec413ec07ce2a2ea9960f112f4ac1af59943fde6
BLAKE2b-256 checksum
How to use checksums
1e3a20b5e9685f8c1537d191dab113646e95c5bec8b9d508ba8f3d55f84d56d3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 3, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 release files

0.4.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page