didis-py
Official Python SDK for the DID.is public API: DID resolution with evidence, W3C DID Resolution, verifiable credentials, explicit policies, and MCP/A2A agent trust. Sync and async clients on httpx; Python 3.11+. Responses are plain dicts typed with TypedDict (didis.types), so editors and mypy know their shape.
The distribution is didis-py; the import name is didis.
Install
pip install didis-py
Usage
from didis import DidisClient, AsyncDidisClient, DidisError
# Defaults to the public API at https://did.is/api; pass base_url when self-hosting.
with DidisClient() as didis:
r = didis.resolve("did:web:identity.foundation")
print(r["verdict"]["headline"])
for d in r["dimensions"]:
print(d["label"], d["state"])
# DID Resolution v1 (W3C CR Draft HTTPS binding, unmodified)
w3c = didis.resolve_w3c("did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK")
# Live resolution stream (server-sent events)
for event, data in didis.stream("did:web:identity.foundation"):
if event == "stage":
print(data["label"], data["status"])
# Credentials: VC DM 2.0 / 1.1, Data Integrity (eddsa-jcs-2022, ecdsa-jcs-2019), VC-JOSE/VC-JWT
credential = {
"@context": ["https://www.w3.org/ns/credentials/v2"],
"type": ["VerifiableCredential"],
"issuer": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK",
"validFrom": "2026-01-01T00:00:00Z",
"credentialSubject": {"id": "did:key:z6MkiTBz1ymuepAQ4HEHYSF1H8quG5GLdmQR63zLFKfvUwi3"},
}
vc = didis.verify_credential(credential)
print(vc["status"], vc["headline"])
# Policies are explicit rules, never scores
out = didis.evaluate_policy(
"did:web:example.com",
{"rules": {"allowedMethods": ["web", "webvh"], "domainBinding": "required"}},
)
print(out["evaluation"]["status"])
# Agents
mcp = didis.inspect_mcp("https://mcp.example.com/mcp")
print(mcp["status"], mcp["inventoryHash"], len(mcp["tools"]))
chain: list[str] = [] # delegation receipt JWS strings, root first
decision = didis.authorize(chain, "payments.refund", trusted_roots=["did:web:example.com"])
print(decision["authorization"]["decision"])
try:
didis.resolve("did:web:does-not-exist.invalid")
except DidisError as e:
print(e.status, e.problem.get("code"), e.problem.get("detail"))
async def main() -> None:
async with AsyncDidisClient() as didis:
diff = await didis.diff("did:web:example.com")
print(diff)
Identifiers are percent-encoded exactly once (quote(did, safe="")). Non-2xx responses raise DidisError with the RFC 9457 problem body.
Guard agent tools
A guarded tool function runs only when (1) the tool definition the agent received still matches the one you approved and (2) DID.is says the agent's registered delegation grants the tool. Every failure raises DidisGuardError and the function does not run (fail-closed).
import os
from didis import DidisClient, DidisGuard, pin_tool_definitions
didis = DidisClient()
# Once, after reviewing the server's tools/list: store these pins in your config.
pins = pin_tool_definitions(reviewed_tools)
guard = DidisGuard(
didis,
agent=os.environ["AGENT_DID"], # from configuration, never from model output
root=os.environ["ROOT_DID"], # require this delegation root
pins=pins,
require_pins=True,
)
@guard.tool("github:create_issue", definition=lambda: current_tools["github:create_issue"])
def create_issue(title: str, body: str) -> dict:
return github.create_issue(title, body)
- The definition check is local (RFC 8785 JCS + SHA-256, the same
definitionSha256DID.is reports) and makes no network call. - The delegation check calls
verify_tool. An ALLOW is reused for 30 s by default (allow_cache_seconds), never past the delegation expiry; DENY and errors are never cached. - Error codes:
TOOL_DRIFT,TOOL_DEFINITION_MISSING,TOOL_NOT_AUTHORIZED,GUARD_UNAVAILABLE,GUARD_MISCONFIGURED. - One tool only:
@didis_guard(client, agent, "github:create_issue", root, pin=..., definition=...). WithAsyncDidisClientuseAsyncDidisGuard(ordidis_guard, which picks it automatically) onasync deffunctions. attest_mcp_pins(client, endpoint, pins)asks DID.is to inspect a public MCP server and compares its hashes with your pins. Run it at startup or deploy time, not per call: it is an outbound, rate-limited request, and servers that need login or run on a private network cannot be inspected.
Webhooks
Console project monitor events use verify_customer_monitor_signature:
from didis import verify_customer_monitor_signature
ok = verify_customer_monitor_signature(
secret,
raw_body,
request.headers["X-DIDIS-Signature"],
tenant_id=tenant_id,
project_id=project_id,
event_id=request.headers["X-DIDIS-Event-ID"],
)
For self-hosted admin daemon monitoring deliveries, use verify_webhook_signature:
from didis import verify_webhook_signature
ok = verify_webhook_signature(
secret,
request.headers["x-didis-timestamp"],
raw_body,
request.headers["x-didis-signature-256"],
)
Public API reference: https://did.is/developers. Monitoring routes need admin_token= and are only available on self-hosted deployments; they are not exposed by the public API.
License
MIT
Metadata
Release files for didis-py 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| didis_py-0.2.0.tar.gz | 19.3 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| didis_py-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 36.4 kB
Release files / didis_py-0.2.0.tar.gz
| Download URL | didis_py-0.2.0.tar.gz |
|---|---|
| Size | 19.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7dfdd4737e95cfb792b3430aa8e0ec01d9dd77c0c35fb6150f7263c091d8b7bd
|
|
BLAKE2b-256 checksum How to use checksums |
2e8ca879268eb96c50bbf09e44ae64c0c6098bb1cbdf26aa15150d5578541c0f
|
| 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 13, 2026.
Transparency logRelease files / didis_py-0.2.0-py3-none-any.whl
| Download URL | didis_py-0.2.0-py3-none-any.whl |
|---|---|
| Size | 17.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
bcd35eca2a58164ebd46f7ccb1b75820cb8d903969834d0a6213968e26397b09
|
|
BLAKE2b-256 checksum How to use checksums |
499f07b8aa19e8f1728aeeb09a7ccb63e5b67fedfe1a39beccc2902470f539b6
|
| 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 13, 2026.
Transparency logSecurity for didis-py 0.2.0
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.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for didis_py-0.2.0.tar.gz
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 13, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.