Developer center
Two surfaces, one resolver: the W3C DID Resolution HTTPS binding for interoperability, and the DID.is evidence API for everything a verifier needs to explain its decision. Free and anonymous to start; no key required.
Quickstart
The public API needs no account and no key. Resolve any supported identifier and you get the W3C result plus the evidence behind it: a plain-language verdict, independently evaluated dimensions, and the stated limits of what was checked.
- Install the SDK for your language, or use any HTTP client.
- Resolve an identifier and read verdict.headline and dimensions.
- Branch on the stable problem code when a request fails, and honour Retry-After.
- When you need metered private resolution, monitoring or signed webhooks, create a project in the console.
Supported methods: did:web, did:webvh, did:key, did:jwk. No scores, no paid ranking: the response is identical for every caller.
# Nothing to install.
curl -s "https://did.is/api/v1/resolve/did%3Aweb%3Aidentity.foundation"
SDKs & CLI
Official, MIT-licensed clients with typed responses for resolution, credentials, policies, agents and fast verify. Both default to https://did.is/api; pass another base URL to target a staging or self-hosted deployment.
npm install @didis/client
import { DidisClient } from "@didis/client";
const didis = new DidisClient();
const r = await didis.resolve("did:web:example.com");Node 18+, browsers and edge runtimes (fetch + WebCrypto). · npm · source
pip install didis-py
from didis import DidisClient
client = DidisClient()
r = client.resolve("did:web:example.com")Python 3.11+, sync and asyncio (AsyncDidisClient), TypedDict responses. · PyPI · source
curl -s "https://did.is/api/v1/fast-verify/did/did%3Aweb%3Aexample.com" # W3C DID Resolution HTTPS binding curl -s -H 'Accept: application/did-resolution' \ "https://did.is/api/1.0/identifiers/did%3Aweb%3Aexample.com"
Plain JSON over HTTPS. Resolver clients that speak the W3C HTTPS binding can use the /1.0/identifiers binding unchanged.
Typed errors
DidisError carries the RFC 9457 problem, status and Retry-After.
Live stages
stream() yields each resolution stage over SSE as it completes.
Webhook helpers
Constant-time signature verification for monitor events.
Timeouts
30 s default per request; configurable in both SDKs.
Base URL & encoding
- Base URL. All paths below are relative to https://did.is/api. HTTPS only.
- Identifiers in paths. Send the DID raw or fully percent-encoded (did%3Aweb%3A…); it is decoded exactly once. Encode # as %23 and ? as %3F in DID URLs. The SDKs do this for you.
- Content types. Responses are application/json; failures are application/problem+json; the W3C binding negotiates application/did-resolution or application/did.
- Bodies. POST bodies are JSON, at most 512 KiB.
- OpenAPI. The full public surface is described as OpenAPI 3.1 at https://did.is/api/openapi.json. Import it into Postman, Insomnia or a client generator; it is built from this page's own catalogue.
- Privacy. Public resolutions are observed and may appear in the identifier's public history. Use the private API for identifiers you must not disclose.
# did:web:example.com#key-1 curl -s "https://did.is/api/v1/dereference/did%3Aweb%3Aexample.com%23key-1"
Rate limits
The public API is free and anonymous, protected by per-client token buckets. Exceeding a bucket returns 429 RATE_LIMITED with Retry-After in seconds. Back off for at least that long; the SDKs expose it on the error.
| Budget | Applies to | Limit |
|---|---|---|
| Standard | Every public request except health | 20 / min |
| Intensive | Streams, did:webvh, credential and policy verification, MCP/A2A inspection, delegation (marked intensive below). Also counts toward Standard. | 2 / min |
| Private API | Project API keys from the console | Per plan |
Under momentary load a request can also return 503 CAPACITY_EXHAUSTED; retry with exponential backoff. Cache results you reuse: verdicts include observedAt.
Errors
Every error is an RFC 9457 problem object with a stable code. Branch on code, not on title or detail. DID Resolution errors use W3C type URIs; DID.is conditions use https://did.is/problems#…. Failures on /v1/resolve include the partial trace.
| Code | /v1 status | W3C status | Meaning |
|---|---|---|---|
| INVALID_DID | 400 | 400 | Syntax or method-specific identifier is invalid (incl. IP-literal did:web). |
| INVALID_DID_URL | 400 | 400 | Malformed DID URL or DID parameters. |
| INVALID_OPTIONS | 400 | 400 | Invalid DID resolution options, e.g. unknown parameter. |
| INVALID_REQUEST | 400 | — | Malformed body, unknown or repeated query parameter. |
| NOT_FOUND | 404 | 404 | Document, version, fragment, service or API route not found. |
| METHOD_NOT_ALLOWED | 405 | — | HTTP method not allowed on this public route. |
| REPRESENTATION_NOT_SUPPORTED | 406 | 406 | Accept header cannot be satisfied. |
| — | — | 410 | W3C binding only: the DID is deactivated (the resolution result is still returned). |
| PAYLOAD_TOO_LARGE | 413 | 500 | Body over the cap (512 KiB requests, 1 MiB fetched documents). |
| INVALID_DID_DOCUMENT | 422 | 500 | Document id mismatch, bad JSON, or failed did:webvh log verification. |
| RATE_LIMITED | 429 | 429 | Anonymous budget exhausted. Honour Retry-After. |
| METHOD_NOT_SUPPORTED | 501 | 501 | DID method not implemented. |
| FEATURE_NOT_SUPPORTED | 501 | 501 | e.g. DID URL paths. |
| EGRESS_BLOCKED | 403 | 500 | Target resolves to a non-public address, or scheme/userinfo refused. |
| UPSTREAM_UNAVAILABLE | 502 | 500 | The identifier's host failed or timed out. |
| CAPACITY_EXHAUSTED | 503 | — | Bounded work capacity is momentarily full; retry with backoff. |
| INTERNAL_ERROR | 500 | 500 | Unexpected internal resolver error. |
HTTP/2 429
content-type: application/problem+json
retry-after: 3
{
"type": "https://did.is/problems#RATE_LIMITED",
"title": "Rate limited",
"status": 429,
"code": "RATE_LIMITED",
"detail": "anonymous Explorer safety budget exhausted"
}import { DidisClient, DidisError } from "@didis/client";
const didis = new DidisClient();
try {
const r = await didis.resolve("did:web:identity.foundation");
console.log(r.verdict.headline);
} catch (e) {
if (e instanceof DidisError && e.problem.code === "RATE_LIMITED") {
const wait = Number(e.problem.retryAfter ?? 1);
console.warn(`Rate limited; retry after ${wait}s`);
}
throw e;
}Private API & webhooks
Projects in the console add metered private resolution that is never written to public history, project API keys with one-time secrets and rotation, hourly identifier monitoring, and signed webhooks. Plans and allowances are on pricing.
- Keys are shown once. Keep them server-side; never ship them to browsers or mobile apps.
- Webhooks carry X-DIDIS-Event-ID and X-DIDIS-Signature: t=<createdAt>,v1=<hex HMAC-SHA256> over createdAt + "." + raw body.
- Verify against the exact raw bytes before parsing. Retries resend the identical event, so record the event ID before side effects and acknowledge duplicates with 2xx.
- Failed deliveries retry up to five attempts (after 1, 2, 4 and 8 minutes). Only HTTPS endpoints on port 443 and public addresses are accepted; redirects are not followed.
import { verifyCustomerMonitorSignature } from "@didis/client";
const secret = process.env.DIDIS_WEBHOOK_SECRET ?? "";
const tenantId = "tenant_0000000000000000000000000000000000000000000000000000000000000000";
const projectId = "project_0000000000000000000000000000000000000000000000000000000000000000";
const body = await req.text(); // raw body, before JSON parsing
const ok = await verifyCustomerMonitorSignature(
secret, body, req.headers.get("x-didis-signature") ?? "",
{ tenantId, projectId, eventId: req.headers.get("x-didis-event-id") ?? "" },
);
if (!ok) return new Response(null, { status: 400 });API reference · Resolution
W3C DID Resolution (CR Draft)
DID Resolution v1 · W3C Candidate Recommendation Draft (1 Oct 2026) HTTPS binding. Accept: application/did-resolution returns the full resolution result; application/did (or */*) returns the DID document only. Errors are RFC 9457 problem objects in didResolutionMetadata.error with the specification's status codes (400 invalid DID, 404 not found, 406 representation not supported, 410 deactivated, 501 method not supported). DID URLs (fragments, ?service=, ?versionId=) are dereferenced.
| Parameter | In | Type | Description |
|---|---|---|---|
| did (required) | path | DID or DID URL | Raw or fully percent-encoded (did%3A…); decoded exactly once. |
| Accept | header | media type | application/did-resolution | application/did |
Returns ResolutionResult or DID document
curl -s "https://did.is/api/1.0/identifiers/did%3Aweb%3Aidentity.foundation" \ -H 'Accept: application/did-resolution'
Resolve with evidence
Superset of the W3C result: verdict (plain-language headline and statements), seven independently evaluated evidence dimensions, the evidence graph, per-stage telemetry, key/linkage/TLS/history evidence and stated limitations. No scores.
| Parameter | In | Type | Description |
|---|---|---|---|
| did (required) | path | DID | The identifier to resolve. |
| noCache | query | boolean | Bypass and refresh the resolver cache. |
Returns EnrichedResolution
curl -s "https://did.is/api/v1/resolve/did%3Aweb%3Aidentity.foundation"
Live resolution (SSE)
Server-sent events: one `stage` event per telemetry stage as it completes, then `result` (EnrichedResolution) or `error` (problem), then `done`.
| Parameter | In | Type | Description |
|---|---|---|---|
| did (required) | path | DID | The identifier to resolve. |
| noCache | query | boolean | Resolve fresh. |
Returns text/event-stream
curl -sN "https://did.is/api/v1/stream/did%3Aweb%3Aidentity.foundation?noCache=true"
Dereference a DID URL
Selects a verification method or service by fragment, a service endpoint by ?service= (with path-traversal-safe relativeRef), or a did:webvh version by versionId / versionTime / versionNumber. Encode '#' as %23.
| Parameter | In | Type | Description |
|---|---|---|---|
| didUrl (required) | path | DID URL | e.g. did:web:example.com%23key-1 |
Returns DereferencingResult
curl -s "https://did.is/api/v1/dereference/did%3Aweb%3Aidentity.foundation%23key-1"
Evidence graph
The nodes and edges behind a verdict (subject, document, origin, TLS, keys, services, linkage) with the state of every relation. Use it to render or audit why a verdict was reached.
| Parameter | In | Type | Description |
|---|---|---|---|
| did (required) | path | DID | The identifier. |
Returns { did, observedAt, verdict, nodes, edges }
curl -s "https://did.is/api/v1/graph/did%3Aweb%3Aidentity.foundation"
API reference · Observation
Observation history
Snapshots DID.is recorded for this identifier (coalesced when unchanged). Observations are records, not proofs of history.
| Parameter | In | Type | Description |
|---|---|---|---|
| did (required) | path | DID | The identifier. |
Returns { did, count, history: ObservationRecord[] }
curl -s "https://did.is/api/v1/history/did%3Aweb%3Aidentity.foundation"
Semantic diff
Compares two observations: keys added, removed and rotated (same id, new material), relationship changes, services, controller, alsoKnownAs, @context and domain-binding changes. Defaults to the latest two distinct observations.
| Parameter | In | Type | Description |
|---|---|---|---|
| did (required) | path | DID | The identifier. |
| from | query | sha256 | Older document hash. |
| to | query | sha256 | Newer document hash. |
Returns SemanticDiff
curl -s "https://did.is/api/v1/diff/did%3Aweb%3Aidentity.foundation"
API reference · Credentials
Verify a credential
Data Integrity (eddsa-jcs-2022, ecdsa-jcs-2019), VC-JWT 1.1 and vc+jwt. The signing key must belong to the issuer DID and be authorised for assertionMethod. Bitstring Status List entries are fetched, their list credential verified, and evaluated fail-closed. Status precedence: MALFORMED > INVALID > UNSUPPORTED > REVOKED > SUSPENDED > EXPIRED > NOT_YET_VALID > INDETERMINATE > VALID.
| Parameter | In | Type | Description |
|---|---|---|---|
| credential (required) | body | object | string | Credential object, raw JSON string, or compact JWT. Raw text preserves member identity. |
| expectedAudience | body | string | Optional expected JWT recipient. Without it, audience is explicitly not verified. |
Returns CredentialVerification
curl -s -X POST "https://did.is/api/v1/credentials/verify" \
-H 'Content-Type: application/json' \
-d '{"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"}}}'Evaluate a policy
Evaluates declarative rules (allowedMethods, allowedCurves, minKeyBits, requireKeyRelationship, domainBinding, tlsMinDaysRemaining, verifiableHistory, maxCacheAgeSeconds, credentialStatus, credentialIssuerMustBeSubject) against observed evidence. Unevaluable rules are INDETERMINATE, never PASS.
| Parameter | In | Type | Description |
|---|---|---|---|
| did (required) | body | string | Subject DID. |
| policy (required) | body | { name?, rules } | Rule set. |
| credential | body | object | string | Optional credential to evaluate. |
Returns { evaluation, credential, resolution }
curl -s -X POST "https://did.is/api/v1/policies/evaluate" \
-H 'Content-Type: application/json' \
-d '{"did":"did:web:identity.foundation","policy":{"rules":{"didResolution":"required","domainBinding":"required"}}}'API reference · Agents
Inspect an MCP server
Streamable HTTP: server/discover (2026-07-28) with legacy initialize fallback; paginated tools/list; SHA-256 fingerprints of every tool definition (RFC 8785); declared annotations vs heuristic side-effect classes; risk signals; drift against the previous observation. 401 responses are reported, never bypassed.
| Parameter | In | Type | Description |
|---|---|---|---|
| endpoint (required) | query | https URL | The MCP endpoint. |
Returns McpInspection
curl -s "https://did.is/api/v1/mcp/inspect?endpoint=https%3A%2F%2Fmcp.example.com%2Fmcp"
Inspect an A2A agent card
Fetches /.well-known/agent-card.json (legacy agent.json fallback), validates the A2A 1.0 shape, and verifies signatures[] (JWS over the JCS card) with keys from a DID kid or an HTTPS jku.
| Parameter | In | Type | Description |
|---|---|---|---|
| url (required) | query | https URL | Agent origin or card URL. |
Returns A2aInspection
curl -s "https://did.is/api/v1/a2a/inspect?url=https%3A%2F%2Fagent.example"
Verify a delegation chain
DID.is Delegation Receipt v1 (experimental): compact JWS receipts, root first. Verifies signatures via capabilityDelegation keys, issuer/audience and prf hash linkage, temporal containment, capability attenuation, acyclicity and depth ≤ 8. register: true stores VALID chains for /v1/agents/verify-tool.
| Parameter | In | Type | Description |
|---|---|---|---|
| chain (required) | body | string[] | Receipts, root first. |
| trustedRoots | body | string[] | Acceptable root DIDs. |
| register | body | boolean | Store if VALID. |
Returns { result: DelegationChainResult, registered }
curl -s -X POST "https://did.is/api/v1/agents/verify-delegation" \
-H 'Content-Type: application/json' \
-d '{"chain":[],"trustedRoots":["did:web:bank.example"]}'Check a registered agent
Answers ALLOW or DENY for an agent and tool against delegation chains previously registered with verify-delegation (register: true). Without a registered VALID chain the answer is DENY.
| Parameter | In | Type | Description |
|---|---|---|---|
| agent (required) | query | DID | The acting agent. |
| tool (required) | query | string | Tool name. |
| root | query | DID | Require this delegation root. |
Returns { agent, tool, decision, authorized, reason }
curl -s "https://did.is/api/v1/agents/verify-tool?agent=did%3Aweb%3Aagent.example&tool=transfer"
API reference · Fast verify
Fast DID verdict
Compact projection for gateways and agents: outcome, headline, dimension states, keys and document hash. Served from cache when fresh.
| Parameter | In | Type | Description |
|---|---|---|---|
| did (required) | path | DID | The identifier. |
| noCache | query | boolean | Bypass and refresh the resolver cache. |
Returns { did, resolved, outcome, headline, statements, dimensions, keys, domainBinding, documentSha256, observedAt, cached }
curl -s "https://did.is/api/v1/fast-verify/did/did%3Aweb%3Aidentity.foundation"
Verify a JWS against a DID
Resolves the DID in the JWS kid, requires the key in assertionMethod or authentication (or the relationship you name), and verifies the signature.
| Parameter | In | Type | Description |
|---|---|---|---|
| jws (required) | body | string | Compact JWS with a DID URL kid. |
| relationship | body | string | Required verification relationship. |
Returns { status, valid, headline, signer, relationship, payload }
curl -s -X POST "https://did.is/api/v1/fast-verify/jws" \
-H 'Content-Type: application/json' \
-d '{"jws":"eyJhbGciOiJFZERTQSIsImtpZCI6ImRpZDprZXk6ejZNa2hhWGdCWkR2b3REa0w1MjU3ZmFpenRpR2lDMlF0S0xHcGJubkVHdGEyZG9LI2tleS0xIn0.eyJzdWIiOiJkaWQ6a2V5Ono2TWtoYVhnQlpEdm90RGtMNTI1N2ZhaXp0aUdpQzJRdEtMR3Bibm5FR3RhMmRvSyJ9.c2lnbmF0dXJl"}'API reference · Directory
Verified control claims
Current, unexpired proofs that a controller demonstrated control of this DID (for example a key signature), each stating what it proves and what it does not. A claim is not legal identity.
| Parameter | In | Type | Description |
|---|---|---|---|
| did (required) | path | DID | The identifier. |
Returns { did, claims: Claim[], listing, note }
curl -s "https://did.is/api/v1/claims/did%3Aweb%3Adid.is"
Search the directory
Identifiers whose controller proved control and opted in to be listed. Listings cannot be bought. Unknown or repeated parameters are rejected.
| Parameter | In | Type | Description |
|---|---|---|---|
| q | query | string | Free text, up to 100 characters. |
| method | query | string | DID method filter, e.g. web, key, webvh. |
| limit | query | integer | 1–50 (default 20). |
| cursor | query | string | nextCursor from the previous page. |
Returns { entries: DirectoryEntry[], nextCursor, note }
curl -s "https://did.is/api/v1/directory?method=web&limit=5"
API reference · Service
Health and capabilities
Liveness plus the supported DID methods and implemented standard versions. Not rate limited.
Returns { status, name, version, time, supportedMethods, standards, monitoring, rateLimited }
curl -s "https://did.is/api/health"
Service status
Machine-readable component status behind did.is/status: resolution, console, billing, monitoring and more.
Returns { status, checkedAt, components: Component[] }
curl -s "https://did.is/api/v1/status"