Skip to content

SDKs

The SDKs are thin clients for the public API: one method per endpoint, typed responses and a single error type. They do the routine work for you: the base URL, encoding identifiers, timeouts and turning error responses into exceptions.

The SDKs add no checks of their own. Every result comes from the API and means exactly what the API page for that endpoint says. Anything the SDKs do not cover, you can call over HTTP.

Your codedidis.resolve(…)
The SDK handles
  • Base URL https://did.is/api
  • Percent-encodes identifiers once
  • 30-second timeout by default
  • Non-2xx answers become DidisError
Your coderesult or DidisError
TypeScript Python
Package @didis/client 0.2.5 didis-py 0.2.5 (import didis)
Source did-is/didis-js did-is/didis-py
Runtime Any runtime with fetch: Node 18+, Deno, Bun, browsers, edge. Zero dependencies, ESM. Python 3.11+, httpx. Sync DidisClient and async AsyncDidisClient.
Responses Typed objects Plain dicts typed with TypedDict (didis.types)
Timeout new DidisClient({ timeoutMs }), default 30 000 DidisClient(timeout=…), default 30.0 seconds
  • Retries beyond Retry-After. From 0.2.4 the SDKs wait for Retry-After and retry a 429 or 503 up to twice (at most 10 seconds per wait). Other errors raise DidisError at once. Pass retry: false (TypeScript) or retry=False (Python) to handle every retry yourself (see Errors and rate limits).
  • Directory and claims. These endpoints have no SDK method; call them over HTTP (see the API reference).
  • Gateway middleware. There is no ready-made proxy or framework plugin. To guard individual tool handlers, use the SDK guard; Guard agent tools shows how with MCP clients, LangChain and the OpenAI Agents SDK.
Terminal window
npm install @didis/client
import { DidisClient, DidisError } from "@didis/client";
const didis = new DidisClient();
try {
const r = await didis.resolve("did:web:did.is");
console.log(r.verdict.headline);
for (const d of r.dimensions) console.log(d.label, d.state);
} catch (e) {
if (e instanceof DidisError) console.log(e.status, e.problem.code, e.problem.detail);
else throw e;
}

Async Python:

import asyncio
from didis import AsyncDidisClient
async def main() -> None:
async with AsyncDidisClient() as didis:
r = await didis.resolve("did:web:did.is")
print(r["verdict"]["outcome"])
asyncio.run(main())

In Rust, percent-encode the identifier once, and on non-2xx responses read the RFC 9457 problem body and the Retry-After header yourself (see Errors).

Without a key, every call uses the anonymous public API and its per-client budget. With a project API key from the console (SDK 0.2.5 or later), four methods count against your team’s monthly allowance instead: inspectMcp, inspectA2a, authorize and verifyDelegation (inspect_mcp, inspect_a2a, authorize, verify_delegation in Python). The results are the same as without a key.

import { DidisClient } from "@didis/client";
const didis = new DidisClient({ apiKey: process.env.DID_IS_API_KEY });
const decision = await didis.authorize(chain, "payments:refund");
const usage = await didis.usage();
console.log(usage.expensiveUsed, "of", usage.expensiveLimit, "used in", usage.period);
  • The key is sent only for those calls and for usage(). All other methods, and verifyDelegation with register: true, keep using the public API without the key.
  • Keep the key server-side. Read it from an environment variable or a secret store. Never put it in browser or mobile code.
  • No double billing. Each call carries a fresh idempotency key, and the automatic retries reuse it, so a retried request is counted once.
  • usage() returns this month’s allowance for the whole team (all projects share it): period, plus Used, Reserved, Limit and Remaining for the standard and expensive pools. It needs a key and is not counted.
  • When the allowance is used up, these calls raise DidisError with status 429 and code QUOTA_EXHAUSTED until the next month or a plan change. Retrying does not help. Remove the key to fall back to the anonymous public API.

The team’s owners also get an email at 80% and at 100% of each monthly allowance (see Accounts, projects and plans).

What happens What it means What to do
The method returns The API answered 2xx. Read the result fields, for example verdict or status.
DidisError, status 429 or 503 Budget used up, or service busy. problem.retryAfter holds the Retry-After value. Wait that long, then retry.
DidisError, other 4xx The request itself is wrong, or the method or feature is not supported. Fix the request; problem.code says why. Do not retry unchanged.
DidisError, 5xx DID.is or the remote host failed. Retry later.
Timeout No answer within the client timeout. Retry later, or raise the timeout.
TypeScript Python Endpoint
health() health() GET /health
resolve(did, { noCache }) resolve(did, no_cache=…) GET /v1/resolve/{did}
resolveW3c(did) resolve_w3c(did) GET /1.0/identifiers/{did}
dereference(didUrl) dereference(did_url) GET /v1/dereference/{didUrl}
stream(did) stream(did) GET /v1/stream/{did}
history(did) history(did) GET /v1/history/{did}
diff(did, from?, to?) diff(did, …) GET /v1/diff/{did}
graph(did) graph(did) GET /v1/graph/{did}
verifyCredential(vc, { expectedAudience }) verify_credential(vc, …) POST /v1/credentials/verify
evaluatePolicy(did, policy, vc?) evaluate_policy(did, policy, credential=None) POST /v1/policies/evaluate
inspectMcp(endpoint) inspect_mcp(endpoint) GET /v1/mcp/inspect
inspectA2a(url) inspect_a2a(url) GET /v1/a2a/inspect
verifyDelegation(chain, { trustedRoots, register }) verify_delegation(chain, trusted_roots=…, register=…) POST /v1/agents/verify-delegation
authorize(chain, tool, { trustedRoots }) authorize(chain, tool, trusted_roots=…) POST /v1/agents/authorize
verifyTool(agent, tool, root?) verify_tool(agent, tool, root=None) GET /v1/agents/verify-tool
fastVerifyDid(did) fast_verify_did(did) GET /v1/fast-verify/did/{did}
fastVerifyJws(jws, relationship?) fast_verify_jws(jws, relationship=None) POST /v1/fast-verify/jws
usage() (needs a key) usage() (needs api_key) Team allowance this month
verifyCustomerMonitorSignature(…) verify_customer_monitor_signature(…) Webhook signatures

There is no published DID.is command-line tool. Use curl or the SDKs.