Policies
A policy is a set of rules you choose, for example “the DID must use did:web or did:webvh, sign with Ed25519 and have a verified domain binding”. POST /v1/policies/evaluate resolves the DID, checks each rule against the evidence and returns PASS or FAIL per rule, with a reason.
You write the rules; DID.is only evaluates them. There are no weights and no scores. A rule that cannot be evaluated is INDETERMINATE, which never counts as a pass.
- Resolve the DID with evidence
- Evaluate each rule you set
- Check the credential, if supplied
What you get
Section titled “What you get”- One result per rule you set, with the value DID.is observed and a message.
- An overall status that is
FAILif any rule fails. - The full resolution the rules were evaluated against, and the credential result if you sent one.
What it does not tell you
Section titled “What it does not tell you”- Whether to trust the organisation behind the DID. A policy evaluates technical evidence only.
- Anything about rules you did not set. All rules are optional; only the rules in your request are evaluated.
Request
Section titled “Request”{ "did": "did:web:did.is", "policy": { "name": "optional label", "rules": { "didResolution": "required", "domainBinding": "required" } }, "credential": "optional: a credential to check together with the DID"}The endpoint uses the intensive budget (10 requests per minute). See Errors and rate limits.
curl -X POST https://did.is/api/v1/policies/evaluate \ -H 'content-type: application/json' \ -d '{"did":"did:web:did.is","policy":{"rules":{"didResolution":"required","domainBinding":"required"}}}'import { DidisClient } from "@didis/client";
const didis = new DidisClient();const res = await didis.evaluatePolicy("did:web:did.is", { rules: { didResolution: "required", domainBinding: "required" },});console.log(res.evaluation.status, res.evaluation.headline);from didis import DidisClient
with DidisClient() as didis: res = didis.evaluate_policy( "did:web:did.is", {"rules": {"didResolution": "required", "domainBinding": "required"}}, ) print(res["evaluation"]["status"], res["evaluation"]["headline"])#[tokio::main]async fn main() -> Result<(), Box<dyn std::error::Error>> { let r: serde_json::Value = reqwest::Client::new() .post("https://did.is/api/v1/policies/evaluate") .json(&serde_json::json!({ "did": "did:web:did.is", "policy": { "rules": { "didResolution": "required", "domainBinding": "required" } } })) .send() .await? .error_for_status()? .json() .await?; println!("{} {}", r["evaluation"]["status"], r["evaluation"]["headline"]); Ok(())}To evaluate a credential together with the DID, pass it as the third argument (evaluatePolicy(did, policy, credential) / evaluate_policy(did, policy, credential=…)).
Response from the live API (abridged):
{ "evaluation": { "did": "did:web:did.is", "evaluatedAt": "2026-10-13T09:09:08Z", "status": "PASS", "headline": "All 2 evaluated rules pass.", "rulesEvaluated": 2, "rulesPassed": 2, "evaluations": [ { "rule": "didResolution", "status": "PASS", "expected": "required", "observedValue": "RESOLVED", "message": "resolved via did:web (RESOLVED)" }, { "rule": "domainBinding", "status": "PASS", "expected": "VERIFIED", "observedValue": "VERIFIED", "message": "VERIFIED: JWS EdDSA signature verified with Ed25519 key did:web:did.is#key-1" } ] }, "resolution": { "…": "the full resolution" }, "credential": null}Reading the result
Section titled “Reading the result”Rule status |
What it means | What to do |
|---|---|---|
PASS |
The evidence meets the rule. | Nothing. |
FAIL |
The evidence does not meet the rule. message and observedValue say why. |
Reject, or relax the rule if it is too strict for your case. |
INDETERMINATE |
The rule could not be evaluated, for example the DID did not resolve. | Treat it as not passed. |
NOT_APPLICABLE |
The rule does not apply, for example a rule marked "optional", or a TLS rule for a did:key. |
Ignored in the overall status. |
The overall evaluation.status ignores NOT_APPLICABLE rules and is:
FAILif any rule fails,- otherwise
INDETERMINATEif any rule could not be evaluated (or no rule applies), - otherwise
PASS.
All rules are optional. Only the rules you set are evaluated.
| Rule | Value | Passes when |
|---|---|---|
didResolution |
"required" |
The DID resolves and is not deactivated. |
allowedMethods |
e.g. ["web", "webvh"] |
The DID method is in the list. |
allowedCurves |
e.g. ["Ed25519", "P-256"] |
Valid signing keys use one of these curves. |
allowedKeySuites |
e.g. ["Multikey", "JsonWebKey2020"] |
Verification method types are in the list. |
minKeyBits |
number | Keys have at least this strength. |
requireKeyRelationship |
e.g. "assertionMethod" |
A valid key is authorised for this relationship. |
domainBinding |
"required" or "optional" |
The DIF Well-Known DID Configuration verifies. |
tlsMinDaysRemaining |
number | The origin’s certificate is valid for at least this many days. |
linkedAccounts |
1 to 4 origins, e.g. ["https://shop.example"] |
Each website is listed in the DID’s alsoKnownAs and links back to the DID. See Link your websites. |
verifiableHistory |
"required" |
The DID has a cryptographically verifiable history (did:webvh). |
maxCacheAgeSeconds |
number | The result is no older than this. |
credentialStatus |
"active" |
The supplied credential verifies and its status is clear. |
credentialIssuerMustBeSubject |
true |
The supplied credential’s issuer is the evaluated DID. |
Next steps
Section titled “Next steps”- Resolution explains the evidence the rules are evaluated against.
- Credentials explains the credential checks behind
credentialStatus.