Skip to main content

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 definitionSha256 DID.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=...). With AsyncDidisClient use AsyncDidisGuard (or didis_guard, which picks it automatically) on async def functions.
  • 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)

Source distribution for didis-py 0.2.0
File Size Uploaded Provenance
didis_py-0.2.0.tar.gz 19.3 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for didis-py 0.2.0
File Interpreter ABI Platform
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 log

Release 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 log

Security 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.

Select from 2 files

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 log

A 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.

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