didit-sdk
Unofficial, community-maintained Python client for the Didit Identity Verification API.
Highlights
- Ergonomic Sync & Async: Dual-client architecture built on top of high-performance
httpx. - Strictly Typed & Validated: 100% type annotations (PEP 561 compliant with
py.typed) and robust Pydantic v2 domain models. - Didit V3 API Alignment: Full fidelity to upstream V3 schemas (
id_verifications[],liveness_checks[],face_matches[],aml_screenings[],reviews[]) with forward compatibility (extra="allow") and backward-compatible property accessors. - Complete Session Lifecycle: Covers all 10 documented Didit session statuses (
Not Started,In Progress,In Review,Approved,Declined,Expired,Abandoned,Kyc Expired,Resubmitted,Awaiting User) with granular state inspection (is_decided,is_closed,requires_review,requires_user_action). - Cryptographic Security: Constant-time HMAC-SHA256 signature verification (
X-Signature-V2&X-Signature), full UTF-8 Unicode canonical JSON support (ensure_ascii=False,allow_nan=False), and authoritative signed body anti-replay verification with strict header matching. - FastAPI Integration: Plug-and-play
DiditWebhookGuarddependency for securing webhook endpoints with zero boilerplate. - Zero-Network Simulation Mode: Built-in
SimulatedDiditandSimulatedAsyncDiditto run unit tests and local end-to-end user flows completely offline without live credentials. - Resilient Error Hierarchy: Typed exceptions (
DiditAuthenticationError,DiditRateLimitError,DiditNotFoundError,DiditServerError) with automated rate-limit retry duration parsing.
Installation
# Core SDK (httpx + pydantic)
pip install didit-sdk
# With FastAPI integration
pip install "didit-sdk[fastapi]"
Quickstart
1. Synchronous Client
from didit import Didit, SessionStatus
# Initialize client (falls back to DIDIT_API_KEY environment variable if omitted)
client = Didit(api_key="your_api_key", webhook_secret="your_webhook_secret")
# Create a verification session
session = client.sessions.create(
vendor_data="user_12345",
workflow_id="wf_kyc_standard",
callback="https://yourapp.com/kyc/complete",
language="es",
)
print(f"Verification URL: {session.url}")
print(f"Session ID: {session.session_id}")
# Fetch verification decision immediately:
decision = client.sessions.get_decision(session.session_id)
# Or poll until a terminal outcome (Approved or Declined) is reached:
decision = client.sessions.poll_decision(session.session_id, timeout=60.0, interval=2.0)
if decision.status == SessionStatus.APPROVED:
print(f"User approved! Document: {decision.document.document_number}")
2. Asynchronous Client (asyncio)
import asyncio
from didit import AsyncDidit, SessionStatus
async def main():
async with AsyncDidit(api_key="your_api_key") as client:
session = await client.sessions.create(
vendor_data="user_987",
workflow_id="wf_kyc_standard",
)
print(f"Session URL: {session.url}")
decision = await client.sessions.get_decision(session.session_id)
if decision.status.is_terminal:
print(f"Final outcome: {decision.status}")
asyncio.run(main())
Securing Webhooks with FastAPI
Didit dispatches signed HTTP POST events upon verification completion. didit-sdk provides a dedicated FastAPI dependency to verify signatures in constant time and prevent replay attacks:
from fastapi import FastAPI, Depends
from didit import WebhookPayload, SessionStatus
from didit.integrations.fastapi import DiditWebhookGuard
app = FastAPI()
# Guard reads secret from argument or DIDIT_WEBHOOK_SECRET env var
webhook_guard = DiditWebhookGuard(secret="whsec_...")
@app.post("/api/v1/webhooks/didit")
async def handle_didit_event(
payload: WebhookPayload = Depends(webhook_guard),
):
print(f"Received event for session: {payload.session_id}")
if payload.status == SessionStatus.APPROVED:
# Mark user verified in your database
...
elif payload.status == SessionStatus.DECLINED:
# Handle rejection
...
return {"received": True}
Testing & Offline Simulation
Developing without live credentials or mock servers? Use the built-in simulator:
from didit import SimulatedDidit, SessionStatus
# Create in-memory client
sim = SimulatedDidit(webhook_secret="test_secret")
# 1. Create a simulated session
session = sim.sessions.create(vendor_data="dev_user", workflow_id="wf_dev")
assert session.session_id.startswith("sim_")
# 2. Simulate user passing identity check
sim.approve_session(session.session_id)
decision = sim.sessions.get_decision(session.session_id)
assert decision.status == SessionStatus.APPROVED
# 3. Generate signed webhook payloads to test your local receiver
raw_body, headers = sim.generate_webhook_event(session.session_id)
# headers contain valid X-Signature-V2 and fresh X-Timestamp!
Exception Handling
All client errors inherit from DiditError:
from didit import Didit
from didit.errors import (
DiditAuthenticationError,
DiditNotFoundError,
DiditRateLimitError,
DiditServerError,
)
client = Didit()
try:
decision = client.sessions.get_decision("non_existent_session")
except DiditNotFoundError:
print("Session not found")
except DiditRateLimitError as exc:
print(f"Rate limited. Retry after {exc.retry_after} seconds.")
except DiditAuthenticationError:
print("Invalid API key")
except DiditServerError as exc:
print(f"Didit server error ({exc.status_code}): {exc.response_body}")
Environment Variables
| Variable | Default | Description |
|---|---|---|
DIDIT_API_KEY |
None (Required) | Your Didit secret API key |
DIDIT_BASE_URL |
https://verification.didit.me/v3 |
Didit API base URL |
DIDIT_WEBHOOK_SECRET |
None | Shared webhook HMAC secret |
DIDIT_TIMEOUT |
30.0 |
HTTP request timeout in seconds |
DIDIT_MAX_RETRIES |
2 |
Maximum retry attempts for transient errors |
Development & Testing
# Clone the repository
git clone https://github.com/agustin18/didit-sdk.git
cd didit-sdk
# Install dependencies with uv
uv sync --extra dev
# Run unit tests with 100% coverage gate
uv run pytest --cov=didit --cov-report=term-missing
# Lint & Format check
uv run ruff check .
uv run ruff format --check .
# Strict type check
uv run mypy src/didit
License
This project is licensed under the terms of the MIT License.
Metadata
Release files for didit-sdk 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| didit_sdk-0.1.2.tar.gz | 29.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| didit_sdk-0.1.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 53.7 kB
Release files / didit_sdk-0.1.2.tar.gz
| Download URL | didit_sdk-0.1.2.tar.gz |
|---|---|
| Size | 29.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
202994ccdabf4b7d7896029ee7ec1ef8221fa2252ee660940715887dd18337f0
|
|
BLAKE2b-256 checksum How to use checksums |
068f8c4ed664622df169a4267e93619ea31d4f7175af8dda3b95c6f131847ed1
|
| 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 Sep 29, 2026.
Transparency logRelease files / didit_sdk-0.1.2-py3-none-any.whl
| Download URL | didit_sdk-0.1.2-py3-none-any.whl |
|---|---|
| Size | 24.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
826fcb4422e887f237bd7fac112c54a901279152900d14d31ee8871cc05d19bc
|
|
BLAKE2b-256 checksum How to use checksums |
654ca8ee98ba8e822038d3fc9e41926f0c46b54491e92f4532df92b31bfecb51
|
| 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 Sep 29, 2026.
Transparency log