Skip to main content
Loss of provenance

A previous release had provenance metadata, but this release does not. View details.

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",                 # the name in tools/list (pin key)
    definition=lambda: current_tools["github_create_issue"],
    capability="github:create_issue",      # what the delegation must grant
)
def create_issue(title: str, body: str) -> dict:
    return github.create_issue(title, body)

Tool name vs capability. MCP and OpenAI tool names may only contain letters, digits, _, - and ., so a tool cannot be called github:create_issue. DID.is capabilities use : namespaces so that github:* can grant a whole group. Pass both: the tool name is used for the pin and error messages, capability is what DID.is is asked about. Without capability, the tool name is used. A capability must be exact (no *, no empty segments, no spaces); an invalid one raises GUARD_MISCONFIGURED before any network call. Since 0.2.1.

Guarding MCP clients (mcp 2.x), LangChain and the OpenAI Agents SDK: see examples/ and Guard agent tools.

  • 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, capability="github:create_issue", pin=..., definition=...). With AsyncDidisClient use AsyncDidisGuard (or didis_guard, which picks it automatically) on async def functions.
  • on_decision and DidisGuardError.detail include both tool and capability.
  • 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.2

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

Loss of provenance

These files do not have provenance metadata, despite files in a prior release including this data.

We recommend further investigation before installing these files. View details.

Source distribution (sdist)

Source distribution for didis-py 0.2.2
File Size Uploaded Provenance
didis_py-0.2.2.tar.gz 30.4 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for didis-py 0.2.2
File Interpreter ABI Platform
didis_py-0.2.2-py3-none-any.whl Python 3 none any Details

Total release size: 48.9 kB

Release files / didis_py-0.2.2.tar.gz

Loss of provenance

This file belongs to a release without provenance metadata, despite a prior release including this data.

We recommend further investigation before installing this file. View details.

Download URL didis_py-0.2.2.tar.gz
Size 30.4 kB
Tags Source
SHA-256 checksum
How to use checksums
029765a22354be24b6bde4f873d1056213a8fea52ba02a191570cc98928b35f8
BLAKE2b-256 checksum
How to use checksums
eac3ee9f1c00d11c3bd6a18c929f5225dac3e0651331f4c7ebd40f445a6f999c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.3

Release files / didis_py-0.2.2-py3-none-any.whl

Loss of provenance

This file belongs to a release without provenance metadata, despite a prior release including this data.

We recommend further investigation before installing this file. View details.

Download URL didis_py-0.2.2-py3-none-any.whl
Size 18.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6549aec448ad2a7d9fe4bd40a4708f86b84591b33c265a3d8fd743f2ec41762b
BLAKE2b-256 checksum
How to use checksums
b0f3fd62e7cbf0ffc8c2b4888a9fdf8904a6d2b60d2c3589557e2f6731b43091
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.3

Security for didis-py 0.2.2

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.

Loss of provenance

A previous release of these files had provenance metadata, but this release does not.

While this could reflect a routine change by the project maintainers, it may also indicate that the release files have been compromised.

Release comparison

  • Removed 0.2.0 2 files With provenance
  • Added 0.2.2 2 files Without provenance

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