Verification Methods
Endpoints to manage the cryptographic keys associated with a DID. A key registered as a verification method is not operationally useful until it is associated with at least one verification relationship.
addVerificationMethod
POST /api/v1/contract/addVerificationMethod
Registers a new key in the DID.
Body
| Field | Type | Required | Description |
|---|---|---|---|
did | string | yes | DID to update. |
vMethodId | string | yes | ID of the verification method (base64url, 43 chars). Recommended: JWK thumbprint. |
publicKeyType | enum | yes | secp256k1 or JsonWebKey2020. |
publicKey | string | yes | Public key material in the format corresponding to the type (see note). |
from | string | yes | EOA of the signing controller. |
publicKeyType Values
The enum spec includes three values, but only two are operationally supported. publicKeyType determines the format of the publicKey field, not the curve: the actual curve is inferred from the registered material itself.
| Value | Supported | Expected format in publicKey | Valid curves |
|---|---|---|---|
secp256k1 | ✅ | 64 hexadecimal XY bytes (uncompressed, without JWK wrapper) | secp256k1 only |
JsonWebKey2020 | ✅ | JWK serialized as JSON and hex-encoded | Any valid crv contained in the JWK (e.g. secp256k1, P-256) |
P-256 | ❌ | — | Reserved, returns 400 UNSUPPORTED |
How it is stored and resolved
The registry library (@red-isbe/did-isbe-registry) reconstructs the JWK when resolving the DID with two branches (function vmToJwk):
- If the stored
publicKeyis a serialized JWK (caseJsonWebKey2020) → it is returned as is. TheellipticTypethat the API assigned internally is ignored because the JWK already brings its owncrv. - If the stored
publicKeyis pure 64 XY bytes (casesecp256k1or legacy material) → the curve is inferred from theellipticTypeand the JWK is constructed.
This means that a secp256k1 key can be registered in two different ways:
- Via
publicKeyType: "secp256k1"— compact format, 64 XY bytes. - Via
publicKeyType: "JsonWebKey2020"— wrapping a JWK withcrv: "secp256k1". More standard for integrating with the rest of the JOSE stack.
Both resolve to a verificationMethod with type: "JsonWebKey2020" and the correct curve inside the publicKeyJwk.
publicKey Format according to type
secp256k1— Uncompressed hexadecimal public key with prefix0x04(130 chars). Example:0x04<X><Y>.JsonWebKey2020— JWK serialized as a JSON string and hex-encoded. Thedid-gen keys -c <curve>utility produces this format directly asPublic Key (hex of JWK). Valid structures:- P-256:
{ "kty": "EC", "crv": "P-256", "alg": "ES256", "x": "...", "y": "..." } - secp256k1:
{ "kty": "EC", "crv": "secp256k1", "x": "...", "y": "..." }
- P-256:
Example
{
"did": "did:isbe:uc:z12kVar5p6bD5WCjEJcQ18Zyt8XV",
"vMethodId": "WqpsDjTHnYVNvX8qx4a1FER8NgnEBS6DjLbDVrX-Fg4",
"publicKeyType": "JsonWebKey2020",
"publicKey": "0x7b226b7479223a224543222c22637276223a22502d323536...",
"from": "0xAe0E493C67f75381b0954644836A3C16c79D0dFD"
}
Response
200 OK with the unsigned transaction.
revokeVerificationMethod
POST /api/v1/contract/revokeVerificationMethod
Marks a key as revoked. Signatures made with it before notAfter remain valid; subsequent ones do not.
Body
{
"did": "did:isbe:uc:z12kVar5p6bD5WCjEJcQ18Zyt8XV",
"vMethodId": "WqpsDjTHnYVNvX8qx4a1FER8NgnEBS6DjLbDVrX-Fg4",
"notAfter": 1774700000,
"from": "0xAe0E493C67f75381b0954644836A3C16c79D0dFD"
}
| Field | Type | Required | Description |
|---|---|---|---|
did | string | yes | Affected DID. |
vMethodId | string | yes | ID of the key to revoke. |
notAfter | number | yes | Unix timestamp after which the key ceases to be valid. |
from | string | yes | EOA of the signing controller. |
expireVerificationMethodrevoke is used when there is a key compromise; expire when the key reaches the natural end of its life. Functionally both do the same, but the semantics allow verifiers to distinguish reasons.
expireVerificationMethod
POST /api/v1/contract/expireVerificationMethod
Marks a key as expired.
Body
{
"did": "did:isbe:uc:z12kVar5p6bD5WCjEJcQ18Zyt8XV",
"vMethodId": "WqpsDjTHnYVNvX8qx4a1FER8NgnEBS6DjLbDVrX-Fg4",
"notAfter": 2090221463,
"from": "0xAe0E493C67f75381b0954644836A3C16c79D0dFD"
}
The fields are identical to revokeVerificationMethod.
rollVerificationMethod
POST /api/v1/contract/rollVerificationMethod
Atomic rotation: registers a new key, schedules the expiration of the old one, and defines an overlap period.
Body
| Field | Type | Required | Description |
|---|---|---|---|
did | string | yes | Affected DID. |
vMethodId | string | yes | ID of the new key. |
publicKeyType | enum | yes | secp256k1 or JsonWebKey2020. |
publicKey | string | yes | Material of the new public key. |
notBefore | number | yes | Unix timestamp of the start of validity of the new key. |
notAfter | number | yes | Unix timestamp of the expiration of the new key. |
oldVMethodId | string | yes | ID of the old key to rotate. |
duration | number | yes | Overlap period in seconds. The duration during which both keys are valid. |
from | string | yes | EOA of the signing controller. |
Example
{
"did": "did:isbe:uc:z12kVar5p6bD5WCjEJcQ18Zyt8XV",
"vMethodId": "<NEW_THUMBPRINT>",
"publicKeyType": "JsonWebKey2020",
"publicKey": "0x<NEW_HEX_JWK>",
"notBefore": 1774700000,
"notAfter": 2090300000,
"oldVMethodId": "<PREVIOUS_THUMBPRINT>",
"duration": 86400,
"from": "0xAe0E493C67f75381b0954644836A3C16c79D0dFD"
}
In this example, during 24 hours (86400 seconds) both keys are valid; after that time, the old one is automatically expired.
Use Cases
- Periodic rotation of keys due to security policy.
- Algorithm migration (unusual; check compatibility first).
- Scheduled replacement after an event that does not yet compromise the key but makes it advisable to change it.