Creating a DID

View as Markdown
When to use

You already have one DID (provisioned at signup), but you want a second — typically for role separation (one for personal credentials, one for agent operation, one for issuing). DIDs are cheap; create as many as your use case needs.

Before you begin
  • You must be signed in.
  • Your account quota allows the new DID (default: 25 DIDs/account; ops-tunable).
Steps
  1. Navigate to My DIDs (/dids).
  2. Click Create DID (top-right). 3. Choose key type:
    • Ed25519 (default, recommended for credential signing) — see §12.3 Cryptography.
    • secp256k1 — useful if you need EVM-address compatibility or cross-chain interop.
  3. (Optional) attach one or more services (each { id, type, serviceEndpoint }) — these are written into the DID Document.
  4. Click Create. The portal calls POST /api/v1/dids (did.go:56). The request body accepts only two fields: keyType ("Ed25519" or "Secp256k1", defaults to Ed25519) and an optional services[] array.
  5. Watch the status pill go from PendingActive (typically 2–5 seconds on testnet).
API & SDK
cURLTypeScript SDK
$curl -X POST https://adid.dev/api/v1/dids \
> -H "Authorization: Bearer $ACCESS_TOKEN" \
> -H "Content-Type: application/json" \
> -d '{ "keyType":"Ed25519" }'
1const did = await client.createDID({
2 keyType: 'ed25519',
3 // services: [{ id: '#agent', type: 'AgentEndpoint', serviceEndpoint: 'https://agent.example.com' }],
4});
5console.log(did.did, did.txHash);

Response:

1{
2 "did": "did:adi:0x4f3a8d2c...",
3 "didDocument": { "@context": [...], "id": "did:adi:0x4f3a8d2c...", "verificationMethod": [...] },
4 "status": "active",
5 "txHash": "0xc2a8e9..."
6}
Verify

The DID appears in /dids. Resolve it:

$curl https://adid.dev/api/v1/dids/resolve/did:adi:0x4f3a8d2c...
Troubleshooting
CodeCauseFix
429 QUOTA_EXCEEDEDMore than 25 DIDsDeactivate unused ones, or contact ops to raise the quota.
503 CHAIN_UNREACHABLERPC downRetry; status pending will eventually reconcile when RPC returns.
Stuck on pending >60 sReceipt not observedSee §15.7.

3.1.3. The DID Document Explained ##### Overview

A DID Document is a JSON-LD object that describes the DID’s keys and endpoints. The shape conforms to W3C DID Core 1.0 §5. On IDA, your DID Document is autogenerated when the DID is created and editable for service endpoints, delegates, and attributes.

Anatomy
1{
2 "@context": [
3 "https://www.w3.org/ns/did/v1",
4 "https://w3id.org/security/suites/ed25519-2020/v1"
5 ],
6 "id": "did:adi:0x9a2c...",
7 "verificationMethod": [
8 {
9 "id": "did:adi:0x9a2c...#key-1",
10 "type": "Ed25519VerificationKey2020",
11 "controller": "did:adi:0x9a2c...",
12 "publicKeyMultibase": "z6MkrJVnaZkeFzdQrK..."
13 }
14 ],
15 "authentication": ["did:adi:0x9a2c...#key-1"],
16 "assertionMethod": ["did:adi:0x9a2c...#key-1"],
17 "keyAgreement": ["did:adi:0x9a2c...#key-1"],
18 "capabilityInvocation": ["did:adi:0x9a2c...#key-1"],
19 "capabilityDelegation": ["did:adi:0x9a2c...#key-1"],
20 "service": [
21 {
22 "id": "did:adi:0x9a2c...#didcomm-1",
23 "type": "DIDCommMessaging",
24 "serviceEndpoint": "https://adid.dev/api/v1/didcomm/receive"
25 }
26 ]
27}
PropertyPurposeMutability
@contextJSON-LD vocabulary, including the cryptographic suiteplatform-managed
idThe DID itselfimmutable
verificationMethodPublic keys referenced by other propertiesrotatable (§3.1.5)
authenticationKeys used to sign challenges (login, DIDComm)derived from VM
assertionMethodKeys used to sign verifiable credentialsderived from VM
keyAgreementKeys used for ECDH (encrypted DIDComm)derived from VM
serviceEndpoints (DIDComm, agent card, custom)editable (§3.1.4)
Why it matters

Every signature you make in the platform is verified against one of these public keys. If your DID Document is wrong (key revoked, endpoint stale), every relying party will see your verifications fail — silently. Treat the DID Document as your public profile for anything cryptographic.

How it fits

The DID Document is stored on chain in the DIDRegistry contract (see §11.2) and cached in the API’s Postgres. The cache is invalidated by chain events (DIDUpdated, DIDDeactivated). Off-chain readers can either trust the cache (faster) or read directly from chain (more authoritative).

3.1.4. Updating Service Endpoints ##### When to use

You want to add a service endpoint to your DID Document — typically a DIDComm receive URL, an agent card URL, or a custom service for a domain-specific protocol.

Before you begin
  • You own the DID (you cannot edit someone else’s).
  • The endpoint URL is reachable from the public internet (or the receiver explicitly allows non-public URLs).
Steps
  1. Open /dids/:did (DID Detail page).
  2. Scroll to Services, click Add service. 3. Fill in:
    • Type — e.g. DIDCommMessaging, LinkedDomains, AgentCard.
    • Service endpoint — full URL.
    • ID (auto-generated, hash-suffixed).
  3. Click Save. The portal calls PUT /api/v1/dids/{did} (did.go:123) with the merged DID Document. The API verifies you own the DID, signs the chain transaction (using your wallet’s MPC key), and emits DIDUpdated.
API & SDK
cURLTypeScript SDK
$curl -X PUT https://adid.dev/api/v1/dids/did:adi:0x9a2c... \
> -H "Authorization: Bearer $ACCESS_TOKEN" \
> -H "Content-Type: application/json" \
> -d '{
> "service":[{
> "id":"#didcomm-2",
> "type":"DIDCommMessaging",
> "serviceEndpoint":"https://my-mediator.example.com/inbox"
> }]
> }'
1await client.updateDID('did:adi:0x9a2c...', {
2 service: [{
3 id: '#didcomm-2',
4 type: 'DIDCommMessaging',
5 serviceEndpoint: 'https://my-mediator.example.com/inbox',
6 }],
7});
Verify
$curl https://adid.dev/api/v1/dids/resolve/did:adi:0x9a2c...

The new service object should be in the service array.

Troubleshooting
CodeCauseFix
403 NOT_DID_OWNERYour JWT does not own the DIDSign in with the right account.
400 INVALID_SERVICEMissing type, malformed URLRe-check fields; serviceEndpoint must be a string or array of strings.
409 SERVICE_ID_CONFLICTDuplicate idChoose a different id suffix.

3.1.5. Key Rotation ##### When to use

  • You suspect (or know) the key has been compromised.
  • The platform’s recommended rotation cadence (90 days for high-risk DIDs).
  • You are migrating from secp256k1 to Ed25519 for credential signing.
Before you begin
  • You own the DID.
  • You will not need the old key for anything in the next 5 minutes (the rotation is immediate; old key is no longer authoritative).
Steps
  1. Open /dids/:did and click Rotate key. 2. Confirm the key type for the new key (defaults to the same as the existing one).
  2. Click Rotate. The portal calls POST /api/v1/dids/{did}/rotate-key (did.go:197).
  3. Server-side:
    • Verifies caller owns the DID.
    • Generates a new keypair.
    • Builds a new DID Document with the new verificationMethod.
    • Submits updateDID to the DIDRegistry signed by the current (about-to-be-rotated) key. (After this transaction, the old key is no longer in verificationMethod.)
    • Inserts the old key into did_key_history for audit/replay diagnostics.
API & SDK
cURLTypeScript SDK
$curl -X POST https://adid.dev/api/v1/dids/did:adi:0x9a2c.../rotate-key \
> -H "Authorization: Bearer $ACCESS_TOKEN"
1await client.rotateKey('did:adi:0x9a2c...', 'Ed25519');
2// re-resolve to inspect the new verificationMethod
3const updated = await client.resolveDID('did:adi:0x9a2c...');
Verify

Re-resolve the DID. The verificationMethod should now contain the new publicKeyMultibase. The updated field on the DID Document metadata should reflect the new timestamp.

Troubleshooting
CodeCauseFix
403 NOT_DID_OWNERCaller is not the controllerSign in with the right account.
409 KEY_ROTATION_IN_FLIGHTA previous rotation has not finalisedWait 30 s and retry.
503 CHAIN_UNREACHABLERPC downRetry; the API has idempotent retry semantics.

⚠️ Warning — Any active credential signed by the old key remains valid as long as the old key is in the DID’s key history. Verifiers SHOULD check did_key_history (exposed via the DID Document metadata) when validating older VCs. The Verification Engine in the portal does this automatically.

3.1.6. Deactivating a DID ##### When to use

You no longer want anyone to trust this DID for new credentials/presentations. Deactivation is a soft-delete: the DID Document remains resolvable but is flagged deactivated: true, and the platform refuses to use it for issuance, presentation, or DIDComm.

Before you begin
  • You own the DID.
  • You have no active credentials issued by this DID that you intend to revoke first (revoke them before deactivating; afterwards the deactivated DID cannot be used to sign revocation entries).
Steps
  1. Open /dids/:did.
  2. Click Deactivate (red button at the bottom).
  3. Confirm in the modal — type the DID into the confirmation field.
  4. The portal calls DELETE /api/v1/dids/{did} (did.go:166). The handler emits DIDDeactivated on the registry.
API & SDK
cURLTypeScript SDK
$curl -X DELETE https://adid.dev/api/v1/dids/did:adi:0x9a2c... \
> -H "Authorization: Bearer $ACCESS_TOKEN"
1await client.deactivateDID('did:adi:0x9a2c...');
Verify

Resolution still works, but the document metadata shows deactivated: true. Per W3C DID Core 1.0 §5.2, this is the canonical end state.

Troubleshooting
CodeCauseFix
403 NOT_DID_OWNERCaller is not the controllerSign in correctly.
409 ALREADY_DEACTIVATEDDID was already deactivatedNo action needed.
400 ACTIVE_CREDENTIALS_EXISTThe DID is the issuer of active credentialsRevoke or transfer first; see §4.4.

3.1.7. Adding & Revoking Delegates ##### When to use

A delegate is a different DID authorised to act on behalf of yours for a specific purpose (e.g. an agent DID that may sign DIDComm messages on your behalf, or an organisational sub-DID that may issue credentials under your authority). Delegation is the cleaner alternative to sharing keys.

Before you begin
  • You own the principal DID.
  • The delegate’s DID is resolvable.
Steps
  1. Open /dids/:did and scroll to Delegates.
  2. Click Add delegate. 3. Fill:
    • Delegate (delegate) — the delegate’s DID or address, e.g. did:adi:0x4f3a....
    • Type (delegateType) — e.g. sigAuth, veriKey (per ERC-1056 conventions).
    • Validity (validity) — number of seconds (default 86400 = 24 h).
  3. Save. The portal calls POST /api/v1/dids/{did}/delegates (did.go:290). The body is the params object directly: { delegateType, delegate, validity }.
API & SDK
cURL — addcURL — revoke
$curl -X POST https://adid.dev/api/v1/dids/did:adi:0x9a2c.../delegates \
> -H "Authorization: Bearer $ACCESS_TOKEN" \
> -H "Content-Type: application/json" \
> -d '{
> "delegateType":"sigAuth",
> "delegate":"did:adi:0x4f3a...",
> "validity": 86400
> }'
$curl -X DELETE https://adid.dev/api/v1/dids/did:adi:0x9a2c.../delegates \
> -H "Authorization: Bearer $ACCESS_TOKEN" \
> -H "Content-Type: application/json" \
> -d '{ "delegateType":"sigAuth", "delegate":"did:adi:0x4f3a..." }'
Verify
$curl -H "Authorization: Bearer $ACCESS_TOKEN" \
> https://adid.dev/api/v1/dids/did:adi:0x9a2c.../delegates

Returns an array [{ delegate, delegateType, validUntil }].

Troubleshooting
CodeCauseFix
400 INVALID_DELEGATEDID format invalidCheck DID syntax.
404 DELEGATE_NOT_FOUNDDID not resolvableAdd the DID to a public registry first.
409 DELEGATE_EXISTSSame delegate + type already authorisedRevoke first, or use a different type.

3.1.8. DID Attributes ##### When to use

You want to attach a small piece of structured data to your DID — e.g. a service URL, a name, a hash — without modifying the DID Document directly. This mirrors the ERC-1056 attribute mechanism: signed key/value pairs anchored on chain.

Before you begin
  • You own the DID.
  • The attribute name is short (≤32 bytes) and meaningful.
Steps
  1. Open /dids/:did and scroll to Attributes.
  2. Click Set attribute.
  3. Enter:
    • Name — e.g. did/svc/HubService, did/auth/email.
    • Value — string or hex-encoded bytes.
    • Validity — seconds.
  4. Save. Calls POST /api/v1/dids/{did}/attributes (did.go:369).
API & SDK
cURL — setcURL — revoke
$curl -X POST https://adid.dev/api/v1/dids/did:adi:0x9a2c.../attributes \
> -H "Authorization: Bearer $ACCESS_TOKEN" \
> -H "Content-Type: application/json" \
> -d '{
> "name":"did/svc/AgentCard",
> "value":"https://my.agent/.well-known/agent.json",
> "validity":2592000
> }'
$curl -X DELETE https://adid.dev/api/v1/dids/did:adi:0x9a2c.../attributes \
> -H "Authorization: Bearer $ACCESS_TOKEN" \
> -H "Content-Type: application/json" \
> -d '{
> "name":"did/svc/AgentCard"
> }'
Verify

Resolve the DID; the attribute is exposed via the didDocumentMetadata.attributes array (or whatever the resolver returns — see §3.1.9).

Troubleshooting

If a value isn’t appearing, the most common cause is a stale cache. Force a re-resolve with:

$curl https://adid.dev/api/v1/dids/resolve/did:adi:0x9a2c...?refresh=true

3.1.9. Universal DID Resolver Tool ##### When to use

You need to fetch the DID Document for any DID — yours, someone else’s, or a DID from a different method entirely. The universal resolver is the public, no-auth endpoint that does this.

Before you begin

Nothing required. The endpoint is unauthenticated.

Steps
  1. Open the DID Resolver page in the portal (/tools/did-resolver) — or just call the endpoint directly.
  2. Paste the DID into the input field.
  3. Click Resolve.
  4. The portal calls GET /api/v1/dids/resolve/{did} (did.go:29, registered at router.go:74).
Supported methods
MethodHow it resolvesSource
did:adiDIDRegistry.resolveDID()ADI chain (cached in Postgres)
did:keyMultibase decode of public keylocal computation
did:webHTTPS GET /.well-known/did.jsonDNS + HTTPS
did:ethrERC-1056 EthereumDIDRegistryEthereum mainnet RPC
API
cURLTypeScript SDK
$curl https://adid.dev/api/v1/dids/resolve/did:adi:0x9a2c...
1// Universal resolver — works for did:adi, did:key, did:web, did:ethr.
2const { didDocument, didDocumentMetadata } =
3 await client.resolveAny('did:adi:0x9a2c...');
4
5// Or, for did:adi only (authenticated):
6// const didDocument = await client.resolveDID('did:adi:0x9a2c...');

Response shape (per W3C DID Resolution):

1{
2 "didDocument": { "@context":[...], "id":"did:adi:0x9a2c...", ... },
3 "didDocumentMetadata": { "created":"...", "updated":"...", "deactivated":false, "txHash":"0x..." },
4 "didResolutionMetadata":{ "contentType":"application/did+ld+json" }
5}
Verify

Compare the returned key fingerprint against an out-of-band channel (e.g., the issuer’s website, a printed business card). DID Documents are public, but their binding to a real-world entity is your responsibility.

Troubleshooting
CodeCauseFix
404 DID_NOT_FOUNDDID not registeredVerify spelling; check method support.
502 UPSTREAM_ERRORdid:web HTTPS fetch failedCheck the host’s /.well-known/did.json.
410 DID_DEACTIVATEDDID is deactivatedThe document is still returned but flagged.