Saltar al contenido principal

Registro del DID desde la API

Esta página cubre los pasos 3 al 6 del onboarding: crear la transacción de inserción, firmarla off-chain y enviarla a la red. Es el modo directo para integradores que ya tienen el DID y la clave pública generados (pasos 1 y 2 de Onboarding del DID).

La DID Registry API no custodia claves privadas

Todos los endpoints de escritura devuelven una transacción sin firmar. La firma ocurre siempre en el cliente, nunca en el servidor.

Requisitos previos

3. Crear la transacción de inserción

Abre la Swagger UI del entorno y localiza la operación:

POST /api/v1/contract/insertFirstDidDocument

Cuerpo de la petición:

{
"did": "did:isbe:uc:z12kVar5p6bD5WCjEJcQ18Zyt8XV",
"vMethodId": "9lfZ28jdUsYo75lVHmGNIc6oUpkjSFtxiCLjDGn28IM",
"proof": "0x70bc9d8cdf399369f0b213a7da5985e5cd533d85bb5562615c98bfb5ac33d40e491436a3086a87ccaae773cbc20a098ef70928dc24b2c636dc8413965f2959a51c",
"publicKeyType": "secp256k1",
"publicKey": "0x041243f50ac70fc996ccc92a2119ce64b6f70bbf4ca1fd3b292fffa8939d06c4f75143e0f7e23b32139cce3a33d2207f937c0b85714d207877e3eca7137dc33214",
"notBefore": 1774602263,
"notAfter": 2090221463,
"alsoKnownAs": "urn:oid:organizationIdentifier:ISBE",
"from": "0xAe0E493C67f75381b0954644836A3C16c79D0dFD"
}

Significado de cada campo

CampoDescripción
didEl DID generado en el paso 2.
baseDocument (opcional)JSON con el @context del DID Document. Si se omite, se aplica el contexto por defecto.
vMethodIdIdentificador del verification method. 32 bytes aleatorios en base64url (43 caracteres sin padding). Recomendado: thumbprint JWK de la clave pública.
proofFirma ECDSA con la clave privada secp256k1 sobre el material que enlaza el DID con la clave pública. La devuelve directamente did-gen did y demuestra al smart contract que quien envía la transacción controla efectivamente la clave que pretende registrar bajo ese DID.
publicKeyTypePara el primer registro siempre secp256k1.
publicKeyClave pública hexadecimal sin comprimir (con prefijo 0x04).
notBeforeTimestamp Unix (segundos) desde el que la clave es válida. Habitualmente ahora.
notAfterTimestamp Unix de expiración. Recomendado: ~10 años en el futuro.
alsoKnownAsIdentificador alternativo. Para entidades organizativas usa urn:oid:organizationIdentifier:<TU_CODIGO>.
fromEOA derivada de tu secp256k1.
Cálculo rápido de timestamps

Usa epochconverter.com para obtener notBefore (ahora) y notAfter (futuro).

Respuesta

La API devuelve una transacción sin firmar lista para ser firmada:

{
"to": "0x00000000000000000000000000000000000015Be",
"data": "0x648b2748...",
"gasLimit": "0x4c4b40",
"gasPrice": "0xfa0",
"chainId": "0x8131",
"nonce": "0xe",
"value": "0x0",
"from": "0xAe0E493C67f75381b0954644836A3C16c79D0dFD"
}

Cópialo entero para el siguiente paso.

4. Firmar la transacción

La transacción devuelta por la API ya viene con todos los campos necesarios (to, data, gasLimit, gasPrice, chainId, nonce, value, from) en formato hexadecimal JSON-RPC. Solo hay que firmarla con la clave privada de la EOA from. A continuación tienes dos ejemplos equivalentes — usa el que encaje con tu stack.

Opción A — Node.js con ethers.js

npm install ethers
import { Wallet, Transaction } from "ethers";

const PRIVATE_KEY = "0x<PRIVATE_KEY>";
const raw = {
to: "0x00000000000000000000000000000000000015Be",
data: "0x648b2748...",
gasLimit: "0x4c4b40",
gasPrice: "0xfa0",
chainId: "0x8131",
nonce: "0xe",
value: "0x0",
from: "0xAe0E493C67f75381b0954644836A3C16c79D0dFD",
};

const wallet = new Wallet(PRIVATE_KEY);
// `from` no forma parte de la tx serializada — se descarta antes de firmar
const tx = Transaction.from({ ...raw, from: undefined });
const signedRawTransaction = await wallet.signTransaction(tx);

console.log(signedRawTransaction);
// 0x01f9034c8281310e820fa0834c4b40...

Este es exactamente el patrón que usan los scripts internos del repositorio isbe-identity-did-api (scripts/addVM.ts, scripts/initialize.ts).

Opción B — Python con eth_account

pip install eth-account
from eth_account import Account

PRIVATE_KEY = "0x<PRIVATE_KEY>"
raw = {
"to": "0x00000000000000000000000000000000000015Be",
"data": "0x648b2748...",
"gasLimit": "0x4c4b40",
"gasPrice": "0xfa0",
"chainId": "0x8131",
"nonce": "0xe",
"value": "0x0",
}

acct = Account.from_key(PRIVATE_KEY)
# eth_account usa los nombres en snake_case esperados por web3.py
tx = {
"to": raw["to"],
"data": raw["data"],
"gas": int(raw["gasLimit"], 16),
"gasPrice": int(raw["gasPrice"], 16),
"chainId": int(raw["chainId"], 16),
"nonce": int(raw["nonce"], 16),
"value": int(raw["value"], 16),
}
signed = acct.sign_transaction(tx)
print(signed.raw_transaction.hex())
# 01f9034c8281310e820fa0834c4b40...

Opción C — CLI interno cli-tx-save

Si el equipo de ISBE te ha proporcionado el binario cli-tx-save, el comando equivalente es:

./sign-tx sign -p 0x<PRIVATE_KEY> -t '<RESPONSE_BODY>'

Donde <RESPONSE_BODY> es la respuesta JSON completa del paso 3, entre comillas simples.

Resultado

En cualquier caso obtienes una signed raw transaction del tipo:

0x01f9034c8281310e820fa0834c4b40...

Guarda esa cadena completa: es lo que necesitarás en el siguiente paso.

5. Enviar la transacción

En la Swagger UI, localiza:

POST /api/v1/transactions/send

Cuerpo:

{
"signedRawTransaction": "0x01f9034c8281310e820fa0834c4b40..."
}

Respuesta esperada (éxito):

{
"tx_hash": "0xb508e46adfc36822e48dde1d9f1f5d2122a1ce6852cf5e0afe6c978da04648c5",
"receipt": {
"blockHash": "0x52afb6108087cdca826289da40cc7339a4e190922f8480afd924c0ddd9d31109",
"blockNumber": 3907283,
"status": 1,
"from": "0xAe0E493C67f75381b0954644836A3C16c79D0dFD",
"to": "0x00000000000000000000000000000000000015Be",
"gasUsed": "221678",
"logs": [
{
"address": "0x00000000000000000000000000000000000015Be",
"topics": ["0x78c431540f7778eb787241a03d7401cd2c95ddb232c918f172f86e4c804d5439"]
}
]
}
}
Respuestas posibles
  • 200 OK — Transacción minada y recibo disponible.
  • 206 Partial Content — Transacción enviada pero el recibo todavía no está disponible (caso de redes con latencia). El tx_hash ya es válido para consultas.
  • 400 Bad Request — La transacción no se ha podido procesar. Revisa la firma, el nonce y los fondos.

6. Verificar el resultado

Para confirmar que el DID está registrado correctamente, resuelve el DID Document:

GET /api/v1/identifiers/{did}

Llama con Accept: application/did+ld+json o application/did+json. La respuesta debe incluir tu verificationMethod recién registrado.

curl -H "Accept: application/did+ld+json" \
https://did-registry.portal.redisbe.com/api/v1/identifiers/did:isbe:uc:z12kVar5p6bD5WCjEJcQ18Zyt8XV

Próximos pasos

Una vez registrado el DID: