Python ScanUpload API Client for seamless integration into ScanUpload SAAS product
Project description
ScanUpload API Client - Python Integration Guide
ScanUpload enables the integration and the ability to use QR codes to scan and upload files directly from a mobile device to your webapp.
This guide explains how to integrate scan-upload-api-client into a Python application. The client library requires Python 3.11+ and is compatible with:
- FastAPI
- Starlette
- Django (with async views)
- Flask (with async support)
- Any ASGI application
Prerequisites
- Python 3.11+
- A ScanUpload account
- A ScanUpload Client ID and Client Secret
Installation
pip install scan-upload-api-client
If you want to pin to a specific release:
pip install scan-upload-api-client==1.0.0
For ASGI/web framework integration:
pip install scan-upload-api-client[asgi]
Configuration
Configure using environment variables or a .env file:
SCANUPLOAD_TARGET_BASE_URL=https://hub.scanupload.net/api/front-end
SCANUPLOAD_ROUTE_PREFIX=/scanupload-api
SCANUPLOAD_TOKEN_ROUTE=/scanupload-api/token
SCANUPLOAD_STRIP_ROUTE_PREFIX=true
SCANUPLOAD_REQUEST_TIMEOUT=90
SCANUPLOAD_API_CLIENT_BASE_URL=https://hub.scanupload.net
KEYCLOAK_SERVER_URL=https://identity.scanupload.net/
KEYCLOAK_REALM=scanupload-hub
KEYCLOAK_CLIENT_ID=your-client-id
KEYCLOAK_CLIENT_SECRET=your-client-secret
KEYCLOAK_SCOPE=openid profile email scanupload.hub
# Optional: enable HTTPS for FastAPI example
UVICORN_SSL_CERTFILE=C:/path/to/localhost.pem
UVICORN_SSL_KEYFILE=C:/path/to/localhost-key.pem
The example apps in examples/ load configuration in this order:
SCANUPLOAD_DOTENV_PATH(if set).envin the current working directory.envin the repository root- Terminal environment variables
WARNING: Never commit secrets to source control. Use environment variables or a secrets management system.
Basic Usage
Keycloak Token Client
import asyncio
from scan_upload_api_client import KeycloakClient, ScanUploadProxyOptions
async def main():
options = ScanUploadProxyOptions(
keycloak_server_url="https://identity.scanupload.net/",
keycloak_realm="scanupload-hub",
keycloak_client_id="your-client-id",
keycloak_client_secret="your-client-secret",
)
async with KeycloakClient(options) as client:
token = await client.get_client_credentials_token()
print(f"Access token: {token.access_token}")
asyncio.run(main())
Token Provider with Caching
from scan_upload_api_client import TokenProvider, KeycloakClient, ScanUploadProxyOptions
async def main():
options = ScanUploadProxyOptions(
keycloak_server_url="https://identity.scanupload.net/",
keycloak_realm="scanupload-hub",
keycloak_client_id="your-client-id",
keycloak_client_secret="your-client-secret",
keycloak_early_refresh_seconds=120,
)
async with KeycloakClient(options) as keycloak_client:
provider = TokenProvider(keycloak_client, options)
# First call fetches token
token1 = await provider.get_access_token()
# Second call uses cache
token2 = await provider.get_access_token()
assert token1.access_token == token2.access_token
asyncio.run(main())
Download Files
from scan_upload_api_client import ScanUploadApiClient, TokenProvider
async def main():
# Setup token provider...
api_client = ScanUploadApiClient(
base_url="https://hub.scanupload.net",
token_provider=provider,
)
async def process_file(filename: str, content: bytes):
print(f"Processing {filename} ({len(content)} bytes)")
# Save or process file content
await api_client.download_async("session-id-123", process_file)
asyncio.run(main())
Framework Integration
If you are consuming the package from PyPI, install the ASGI extras first:
pip install "scan-upload-api-client[asgi]"
Then create your FastAPI app with the published package:
from fastapi import FastAPI
from contextlib import asynccontextmanager
from scan_upload_api_client import (
KeycloakClient,
ScanUploadProxyOptions,
TokenProvider,
)
from scan_upload_api_client.middleware import ScanUploadProxyMiddleware
options = ScanUploadProxyOptions(
target_base_url="https://hub.scanupload.net/api/front-end",
route_prefix="/scanupload-api",
token_route="/scanupload-api/token",
strip_route_prefix=True,
keycloak_server_url="https://identity.scanupload.net/",
keycloak_realm="scanupload-hub",
keycloak_client_id="your-client-id",
keycloak_client_secret="your-client-secret",
)
@asynccontextmanager
async def lifespan(app: FastAPI):
keycloak_client = KeycloakClient(options)
token_provider = TokenProvider(keycloak_client, options)
app.state.scan_upload_token_provider = token_provider
try:
yield
finally:
await keycloak_client.close()
app = FastAPI(title="ScanUpload FastAPI Example", lifespan=lifespan)
app.add_middleware(ScanUploadProxyMiddleware, options=options)
@app.get("/")
async def root():
return {"message": "ScanUpload API client is active"}
The reusable repository example in
examples/fastapi_example.py follows the same
pattern, adds /token and /download/{session_id} helper routes, and can be
adapted directly into an existing FastAPI service.
You can also integrate the middleware in Starlette:
from contextlib import asynccontextmanager
from starlette.applications import Starlette
from starlette.responses import JSONResponse
from starlette.routing import Route
from scan_upload_api_client import (
KeycloakClient,
ScanUploadProxyOptions,
TokenProvider,
)
from scan_upload_api_client.middleware import ScanUploadProxyMiddleware
options = ScanUploadProxyOptions(
target_base_url="https://hub.scanupload.net/api/front-end",
route_prefix="/scanupload-api",
token_route="/scanupload-api/token",
strip_route_prefix=True,
keycloak_server_url="https://identity.scanupload.net/",
keycloak_realm="scanupload-hub",
keycloak_client_id="your-client-id",
keycloak_client_secret="your-client-secret",
)
async def root(_):
return JSONResponse({"message": "ScanUpload API client is active"})
@asynccontextmanager
async def lifespan(app: Starlette):
keycloak_client = KeycloakClient(options)
token_provider = TokenProvider(keycloak_client, options)
app.state.scan_upload_token_provider = token_provider
try:
yield
finally:
await keycloak_client.close()
app = Starlette(routes=[Route("/", root)], lifespan=lifespan)
app.add_middleware(ScanUploadProxyMiddleware, options=options)
The reusable repository example in
examples/starlette_example.py follows the same
pattern, adds /health, /token, and /download/{session_id} helper routes,
and can be adapted directly into an existing Starlette service.
To run the full FastAPI example app from this repository:
pip install -e .[asgi]
python examples/fastapi_example.py
To run the full Starlette example app from this repository:
pip install -e .[asgi]
python examples/starlette_example.py
By default, the example runs on http://localhost:7021. If both
UVICORN_SSL_CERTFILE and UVICORN_SSL_KEYFILE are set, it runs on
https://localhost:7021.
Running Tests
# Install test dependencies
pip install -e .[test]
# Run tests
pytest
Compatibility Notes
- Requires Python 3.11+
- Fully async (uses
httpx.AsyncClient) - Thread-safe token caching
- Compatible with FastAPI, Starlette, Django, Flask
License
See the repository license file for terms.
Project details
Release history Release notifications | RSS feed
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 scan_upload_api_client-1.0.2.tar.gz.
File metadata
- Download URL: scan_upload_api_client-1.0.2.tar.gz
- Upload date:
- Size: 16.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9ca5a4c978251a850927f3e84265af3c418d2fc9965cfb20fa56ba98079d506b
|
|
| MD5 |
6b9f3f8318a00d4d6e95ac68ecb8dfb2
|
|
| BLAKE2b-256 |
c3c2bc819dc0f0b8c48b7aee47cb00184cf56a3a8cab589e9ecd1ccff45d59ac
|
File details
Details for the file scan_upload_api_client-1.0.2-py3-none-any.whl.
File metadata
- Download URL: scan_upload_api_client-1.0.2-py3-none-any.whl
- Upload date:
- Size: 12.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
42d40b860f617d5d90bd3d86998c6355c10e697e0021232011011da1cea50ae2
|
|
| MD5 |
7040c0787cfb74b186bdff0106d855ff
|
|
| BLAKE2b-256 |
fc3b067cec554f6da8aedd6f9dd19d3c170c087ffddc796de23727f78c1937ba
|