Issue Certificates
Use the X.509 Certificate Service to issue self-signed roots, CA-signed intermediates and leaves, ISO IACA roots, ISO Document Signer certificates, and ETSI Provider / Wallet Relying Party certificates. Every certificate is issued through one request shape (UpsertGeneratedCertificateRequest) sent to either:
POST /v1/{target}/x509-service-api/certificates— issue a new certificate.PUT /v1/{target}/x509-service-api/certificates— issue or replace the certificate at a known ID.
Service reference: Swagger API Reference
Shared Path Parameters
orgID: When performing operations within an organization, use the organization's Base URL or another valid host alias. For example, if your organization is namedtest, your default Base URL istest.enterprise-sandbox.waltid.devon the sandbox environment.target: The X.509 Certificate service path, optionally suffixed with a certificate ID:{organizationID}.{tenantID}.{x509ServiceID}— forPOST, the service generates a random certificate ID.{organizationID}.{tenantID}.{x509ServiceID}.{certificateID}— issue the certificate under a specific ID. Required forPUT.
Certificate ID and storage
The certificate ID is taken from the request path, not the body. When one or more X.509 Store services are attached, the issued certificate is written into them under that ID (one shared child ID across all attached stores), and the response persistResult maps each full stored path to its outcome. When no store is attached the certificate is generated and returned but not stored, and persistResult is empty.
Request fields
All issuance requests use the same body. validFrom and validTo are always required; everything else depends on the certificate you are issuing.
Store persistence (optional, override the service default — see Store persistence)
createStrategy: String -CREATE_NONE|CREATE_ONE|CREATE_ALL. Applies toPOST.upsertStrategy: String -INSERT_ONE_UPDATE_ALL|UPSERT_ALL. Applies toPUT.successStrategy: String -ANY_OK|ALL_OK.storeRef: String - Target reference of a single X.509 store to write into, e.g.test.tenant1.x509-store-1. When omitted, the store selection follows the strategy.
Certificate shape
certificateProfile: String (optional) - Applies a predefined profile and validates the issued certificate against it. See Certificate profiles for the full list of names and requirements.signatureAlgorithm: String (optional) - Signature algorithm used to sign the certificate. Defaults to an algorithm derived from the issuer key (SHA-256/384/512with ECDSA or RSA PKCS#1 depending on the key).validFrom: String (required) - Validity start (notBefore), ISO-8601 instant, e.g.2026-09-01T00:00:00Z.validTo: String (required) - Validity end (notAfter), ISO-8601 instant.
Subject public key and subject DN (supply exactly one key source)
subjectKeyRef: String - KMS key path for the subject key, e.g.test.tenant1.kms1.leaf-key.subjectKeyJwk: Object - Subject public/private key as a JWK.csrPem: String - PKCS#10 CSR PEM. The subject DN and subject alternative names are taken from the CSR and its signature is verified for proof-of-possession. Cannot be combined withsubjectDnorselfSigned. See CSR Workflows.subjectDn: String - Subject distinguished name, e.g.CN=Example Leaf,O=Example Org,C=US. Required unless a CSR is provided.
Issuer (self-signed, or one issuer source)
selfSigned: Boolean (defaultfalse) - Whentrue, the subject key also signs the certificate. No issuer certificate or issuer DN may be set.issuerCertificateRef: String - Path of a stored issuer certificate, e.g.test.tenant1.x509-store-1.example-iaca. The issuer DN and (if not overridden) the issuer key are taken from it.issuerCertificatePem: String - Issuer certificate PEM, used the same way asissuerCertificateRef. Required when no store is attached and the certificate is not self-signed.issuerKeyRef: String - KMS key path for the signing key. Required if the issuer certificate does not record a subject key reference.issuerKeyJwk: Object - Signing key as a JWK. Mutually exclusive withissuerKeyRef.
For a CA-signed certificate (any issuer other than selfSigned), validFrom / validTo must fall within the issuer certificate's own validity window. A request outside that window fails with 400.
Extensions
keyUsage: Array of Strings - Key usage bits:digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement,keyCertSign,cRLSign,encipherOnly,decipherOnly.extendedKeyUsageOids: Array of Strings - Extended key usage OIDs.basicConstraintsCa: Boolean -truefor a CA certificate,falseto explicitly mark a leaf.basicConstraintsPathLength: Integer - Maximum number of intermediate CAs below this certificate. Only valid whenbasicConstraintsCaistrue.subjectAlternativeNames: Array - SAN entries, each{ "type": ..., "name": ... }withtypeone ofdnsName,email,uri,ipAddress. Overrides SANs carried in a CSR.issuerAlternativeNames: Array - Issuer alternative name entries in the same{ type, name }form.crlDistributionPointUri: String - CRL distribution point URI.authorityInfoAccessCaIssuerUris: Array of Strings - Authority Information Access: URI(s) where the issuing CA's own certificate can be retrieved.authorityInfoAccessOcspResponderUris: Array of Strings - Authority Information Access: URI(s) of OCSP responder(s) for this certificate.certificatePolicyOids: Array of Strings - Certificate Policies extension: OID strings identifying the applicable certificate policies (e.g. a TSP-defined or ETSI policy OID).qcStatements: Object (optional) - RFC 3739 / ETSI EN 319 412-5 Qualified Certificate Statements:qcCompliance: Boolean (defaultfalse) - Asserts the certificate is a qualified certificate (QcCompliance statement).qcSscd: Boolean (defaultfalse) - Asserts the private key resides in a qualified signature/seal creation device (QcSSCD statement).qcTypeOids: Array of Strings - OID(s) naming the certificate type(s) asserted by the QcType statement, e.g.id-etsi-qct-esign/-eseal/-web.otherStatementIds: Array of Strings - Additional statement OIDs not covered above.statementInfois not supported and is omitted.
Metadata
metadata: Object - Arbitrary JSON stored alongside the certificate. The service merges inissuerKeyRef,subjectKeyRef, andissuerCertRef(the resolved references) on top of what you provide. To make a self-signed IACA eligible for a VICAL, includevicalDocTypeas a JSON array of mdoc document types, e.g."vicalDocType": ["org.iso.18013.5.1.mDL"].
Certificate profiles
certificateProfile applies a predefined extension set to the certificate being issued and validates the result against it after issuance. certificateProfile is independent of selfSigned / issuer selection — each profile fixes whether it is self-signed or CA-issued, as shown below.
| Profile | Alias | Standard | Self-signed |
|---|---|---|---|
iso-iaca-root | org.iso.18013.5.1.iaca | ISO/IEC 18013-5 (mDL) | Always |
iso-document-signer | org.iso.18013.5.1.ds | ISO/IEC 18013-5 (mDL) | Never — issued by an IACA |
etsi-pid-provider | — | ETSI TS 119 412-6 | Self-signed or CA-issued |
etsi-wallet-provider | — | ETSI TS 119 412-6 | Self-signed or CA-issued |
etsi-wrpac | — | ETSI TS 119 411-8 | Never — issued by a national WRP provider |
etsi-wrprc | — | ETSI TS 119 475 | Never — issued by a national registrar |
etsi-wrprc is a draft profile: it applies and validates the baseline end-entity certificate shape shared by every ETSI EUDI profile, but does not yet encode or validate the WRPRC-specific "registered intended use" — that requires a custom extension not modelled yet. A generated etsi-wrprc certificate always carries a registeredIntendedUse warning in the service log; it does not fail issuance.
Self-signed root or CA certificate
Set selfSigned: true and provide one key via subjectKeyRef or subjectKeyJwk (or issuerKeyJwk); that key is both subject and signing key.
Endpoint: POST /v1/{target}/x509-service-api/certificates | API Reference
Example Request
curl -X 'POST' \
'https://{orgID}.enterprise-sandbox.waltid.dev/v1/{target}/x509-service-api/certificates' \
-H 'accept: application/json' \
-H 'Authorization: Bearer {yourToken}' \
-H 'Content-Type: application/json' \
-d '{
"selfSigned": true,
"subjectKeyRef": "test.tenant1.kms1.root-key",
"subjectDn": "CN=Example Root CA,O=Example Org,C=US",
"validFrom": "2026-09-01T00:00:00Z",
"validTo": "2031-09-01T00:00:00Z",
"basicConstraintsCa": true,
"basicConstraintsPathLength": 1,
"keyUsage": ["keyCertSign", "cRLSign"]
}'
Body Parameters
selfSigned: Boolean (required here) - Set totrue.subjectKeyRef/subjectKeyJwk: String / Object (required) - The root key. Also used as the signing key.subjectDn: String (required) - Distinguished name of the root.validFrom/validTo: String (required) - Validity window.basicConstraintsCa/basicConstraintsPathLength/keyUsage: mixed (optional) - Recommended for a CA certificate.
Example Response
{
"certificate": {
"_id": "test.tenant1.x509-store-1.b0e0f4b7-2b1a-4a2e-9d9f-6b2f0d5c1a33",
"createdAt": "2026-09-01T09:12:44Z",
"updatedAt": "2026-09-01T09:12:44Z",
"metadata": {
"issuerKeyRef": "test.tenant1.kms1.root-key",
"subjectKeyRef": "test.tenant1.kms1.root-key"
},
"certificatePem": "-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----",
"issuerDn": "CN=Example Root CA,O=Example Org,C=US",
"issuerDnHex": "3045310f...",
"subjectDn": "CN=Example Root CA,O=Example Org,C=US",
"subjectDnHex": "3045310f...",
"validFrom": "2026-09-01T00:00:00Z",
"validTo": "2031-09-01T00:00:00Z"
},
"persistResult": {
"test.tenant1.x509-store-1.b0e0f4b7-2b1a-4a2e-9d9f-6b2f0d5c1a33": "CREATED"
}
}
Response Codes
200- Certificate generated, no store attached (not persisted).201- Certificate issued and persisted.409- A certificate with this ID already exists in an attached store.400- Invalid request (e.g. conflicting key inputs, missing subject DN).401- Invalid or missing authentication token.500- The certificate was generated but a required store write failed (e.g. a store was unreachable). CheckpersistResultfor which store reportedFAILED; safe to retry with the same request.
CA-signed certificate
Omit selfSigned and point at an issuer. The most common source is a stored issuer certificate (issuerCertificateRef); the signing key is read from that certificate's recorded subjectKeyRef metadata unless you override it with issuerKeyRef / issuerKeyJwk.
Endpoint: POST /v1/{target}/x509-service-api/certificates | API Reference
Example Request
curl -X 'POST' \
'https://{orgID}.enterprise-sandbox.waltid.dev/v1/{target}/x509-service-api/certificates' \
-H 'accept: application/json' \
-H 'Authorization: Bearer {yourToken}' \
-H 'Content-Type: application/json' \
-d '{
"issuerCertificateRef": "test.tenant1.x509-store-1.example-root-ca",
"subjectKeyRef": "test.tenant1.kms1.leaf-key",
"subjectDn": "CN=Example Leaf,O=Example Org,C=US",
"validFrom": "2026-09-01T00:00:00Z",
"validTo": "2027-09-01T00:00:00Z",
"keyUsage": ["digitalSignature"],
"subjectAlternativeNames": [
{ "type": "dnsName", "name": "leaf.example.com" }
]
}'
Body Parameters
issuerCertificateRef: String (required here) - Stored issuer certificate. UseissuerCertificatePeminstead when no store is attached.issuerKeyRef/issuerKeyJwk: String / Object (optional) - Override the signing key. Required if the issuer certificate does not record one.subjectKeyRef/subjectKeyJwk/csrPem: mixed (required) - Subject public key source.subjectDn: String (required unlesscsrPemis used) - Leaf distinguished name.
Example Response
{
"certificate": {
"_id": "test.tenant1.x509-store-1.f5a1c0d2-8e7b-4c3a-91d0-2a7e4b9c1f66",
"createdAt": "2026-09-01T09:20:10Z",
"updatedAt": "2026-09-01T09:20:10Z",
"metadata": {
"issuerKeyRef": "test.tenant1.kms1.root-key",
"subjectKeyRef": "test.tenant1.kms1.leaf-key",
"issuerCertRef": "test.tenant1.x509-store-1.example-root-ca"
},
"certificatePem": "-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----",
"issuerDn": "CN=Example Root CA,O=Example Org,C=US",
"issuerDnHex": "3045310f...",
"subjectDn": "CN=Example Leaf,O=Example Org,C=US",
"subjectDnHex": "3043310d...",
"validFrom": "2026-09-01T00:00:00Z",
"validTo": "2027-09-01T00:00:00Z"
},
"persistResult": {
"test.tenant1.x509-store-1.f5a1c0d2-8e7b-4c3a-91d0-2a7e4b9c1f66": "CREATED"
}
}
Response Codes
200- Certificate generated, no store attached.201- Certificate issued and persisted.409- Certificate ID already exists in an attached store.400- Invalid request (e.g. issuer not resolvable, subject DN in CSR mismatch).401- Invalid or missing authentication token.500- The certificate was generated but a required store write failed. CheckpersistResultfor which store reportedFAILED; safe to retry with the same request.
ISO IACA root certificate
Set certificateProfile to iso-iaca-root and selfSigned to true. The profile adds the ISO/IEC 18013-5 IACA extensions (CA=true, pathLenConstraint=0, keyCertSign + cRLSign marked critical, subject key identifier, issuer alternative name) and validates the result. Supported keys: secp256r1, secp384r1, secp521r1.
Endpoint: POST /v1/{target}/x509-service-api/certificates | API Reference
Example Request
curl -X 'POST' \
'https://{orgID}.enterprise-sandbox.waltid.dev/v1/{target}.iaca-prod-2026/x509-service-api/certificates' \
-H 'accept: application/json' \
-H 'Authorization: Bearer {yourToken}' \
-H 'Content-Type: application/json' \
-d '{
"selfSigned": true,
"certificateProfile": "iso-iaca-root",
"subjectKeyRef": "test.tenant1.kms1.iaca-key",
"subjectDn": "CN=Example IACA,O=Example Org,C=US",
"validFrom": "2026-09-01T00:00:00Z",
"validTo": "2036-09-01T00:00:00Z",
"issuerAlternativeNames": [
{ "type": "uri", "name": "https://iaca.example.com" },
{ "type": "email", "name": "iaca@example.com" }
],
"metadata": {
"vicalDocType": ["org.iso.18013.5.1.mDL"]
}
}'
Body Parameters
certificateProfile: String (required here) -iso-iaca-root.selfSigned: Boolean (required here) -true.subjectKeyRef/subjectKeyJwk: String / Object (required) - The IACA key (secp256r1/secp384r1/secp521r1).subjectDn: String (required) - IACA distinguished name.C=must be a valid ISO 3166-1 alpha-2 code.issuerAlternativeNames: Array (required by profile) - At least oneurioremailentry.metadata.vicalDocType: Array of Strings (optional) - Required for this IACA to be picked up by the VICAL Service.
Response Codes
200/201- IACA issued (persisted when a store is attached).400- Profile validation failed (e.g. missing issuer alternative name, invalid country code, validity window too long).401- Invalid or missing authentication token.500- The certificate was generated but a required store write failed. CheckpersistResultfor which store reportedFAILED; safe to retry with the same request.
ISO Document Signer certificate
Set certificateProfile to iso-document-signer and issue against an IACA via issuerCertificateRef (a stored IACA) or issuerCertificatePem. The profile adds the Document Signer extensions (digitalSignature critical, extended key usage 1.0.18013.5.1.2, subject/authority key identifiers, issuer alternative name from the IACA, CRL distribution point) and validates the result.
Endpoint: POST /v1/{target}/x509-service-api/certificates | API Reference
Example Request
curl -X 'POST' \
'https://{orgID}.enterprise-sandbox.waltid.dev/v1/{target}.ds-2026-q1/x509-service-api/certificates' \
-H 'accept: application/json' \
-H 'Authorization: Bearer {yourToken}' \
-H 'Content-Type: application/json' \
-d '{
"certificateProfile": "iso-document-signer",
"issuerCertificateRef": "test.tenant1.x509-store-1.iaca-prod-2026",
"subjectKeyRef": "test.tenant1.kms1.ds-key",
"subjectDn": "CN=Example Document Signer,O=Example Org,C=US",
"validFrom": "2026-09-01T00:00:00Z",
"validTo": "2027-11-01T00:00:00Z",
"issuerAlternativeNames": [
{ "type": "uri", "name": "https://iaca.example.com" }
],
"crlDistributionPointUri": "https://crl.example.com/ds.crl"
}'
Body Parameters
certificateProfile: String (required here) -iso-document-signer.issuerCertificateRef/issuerCertificatePem: String (required) - The issuing IACA.subjectKeyRef/subjectKeyJwk/csrPem: mixed (required) - Document Signer public key source.subjectDn: String (required unlesscsrPemis used) - Document Signer distinguished name. Requires aCN=;C=must match the IACA'sC=, andST=must match the IACA'sST=if the IACA has one.crlDistributionPointUri: String (required by profile) - CRL distribution point.issuerKeyRef/issuerKeyJwk: String / Object (optional) - Override the IACA signing key.
Response Codes
200/201- Document Signer issued (persisted when a store is attached).400- Profile validation failed (e.g. missing commonName, country/state mismatch with the IACA, validity window outside the IACA window or over the profile maximum).401- Invalid or missing authentication token.500- The certificate was generated but a required store write failed. CheckpersistResultfor which store reportedFAILED; safe to retry with the same request.
ETSI PID Provider certificate
Set certificateProfile to etsi-pid-provider. Issues an end-entity certificate for a PID (Personal Identification Data) Provider, per ETSI TS 119 412-6 clause 4 — the certificate whose private key signs SD-JWT VC / mdoc Person Identification Data. May be self-signed or CA-issued. The profile adds basicConstraints{cA=false} and keyUsage{digitalSignature} (both critical), a subject key identifier, and a qcStatements QcCompliance + QcType (id-etsi-qct-pid, 0.4.0.194126.1.1) statement automatically — you do not need to set qcStatements yourself unless you want to assert additional statements.
Endpoint: POST /v1/{target}/x509-service-api/certificates | API Reference
Example Request
curl -X 'POST' \
'https://{orgID}.enterprise-sandbox.waltid.dev/v1/{target}/x509-service-api/certificates' \
-H 'accept: application/json' \
-H 'Authorization: Bearer {yourToken}' \
-H 'Content-Type: application/json' \
-d '{
"selfSigned": true,
"certificateProfile": "etsi-pid-provider",
"subjectKeyRef": "test.tenant1.kms1.pid-provider-key",
"subjectDn": "CN=Example PID Provider,O=Example PID Provider AT,organizationIdentifier=VATAT-U12345678,C=AT",
"validFrom": "2026-09-01T00:00:00Z",
"validTo": "2031-09-01T00:00:00Z",
"certificatePolicyOids": ["1.3.6.1.4.1.55555.1.1"]
}'
Body Parameters
certificateProfile: String (required here) -etsi-pid-provider.selfSigned: Boolean (optional) -truefor a self-signed PID Provider certificate; omit and set an issuer for a CA-issued one.subjectDn: String (required) - Must includeC=andCN=, plusO=(legal person) orgivenName=/surname=/pseudonym=+serialNumber=(natural person). Presence oforganizationIdentifier=selects the legal-person shape. When CA-issued, the issuer certificate's subject DN is validated the same way.certificatePolicyOids: Array of Strings (required by profile) - At least one TSP-defined policy OID.authorityInfoAccessCaIssuerUris/authorityInfoAccessOcspResponderUris: Array of Strings (required by profile unless self-signed) - CA issuer / OCSP responder location(s).
Response Codes
200/201- Certificate issued (persisted when a store is attached).400- Profile validation failed (e.g. missing certificate policy OID, missingauthorityInfoAccesson a CA-issued certificate, malformed subject/issuer DN, unsupported key algorithm/size).401- Invalid or missing authentication token.500- The certificate was generated but a required store write failed. CheckpersistResultfor which store reportedFAILED; safe to retry with the same request.
ETSI Wallet Provider certificate
Set certificateProfile to etsi-wallet-provider. Issues an end-entity certificate for a Wallet Provider, per ETSI TS 119 412-6 clause 5.1 — the certificate whose private key signs Wallet Instance / Unit Attestations (WIA/WUA). Otherwise identical to the ETSI PID Provider certificate: may be self-signed or CA-issued, same DN shape and certificatePolicyOids / authorityInfoAccess requirements, same extensions applied automatically — except the automatic qcStatements QcType OID is id-etsi-qct-wal (0.4.0.194126.1.2).
Endpoint: POST /v1/{target}/x509-service-api/certificates | API Reference
Example Request
curl -X 'POST' \
'https://{orgID}.enterprise-sandbox.waltid.dev/v1/{target}/x509-service-api/certificates' \
-H 'accept: application/json' \
-H 'Authorization: Bearer {yourToken}' \
-H 'Content-Type: application/json' \
-d '{
"selfSigned": true,
"certificateProfile": "etsi-wallet-provider",
"subjectKeyRef": "test.tenant1.kms1.wallet-provider-key",
"subjectDn": "CN=Example Wallet Provider,O=Example Wallet Provider AT,organizationIdentifier=VATAT-U87654321,C=AT",
"validFrom": "2026-09-01T00:00:00Z",
"validTo": "2031-09-01T00:00:00Z",
"certificatePolicyOids": ["1.3.6.1.4.1.55555.2.1"]
}'
Body Parameters
certificateProfile: String (required here) -etsi-wallet-provider.- Same remaining fields as ETSI PID Provider certificate.
Response Codes
Same as ETSI PID Provider certificate.
ETSI Wallet Relying Party Access Certificate (WRPAC)
Set certificateProfile to etsi-wrpac. Issues an end-entity certificate a Relying Party uses to authenticate a presentation request to a wallet, per ETSI TS 119 411-8 clause 6.6.1. Always CA-issued by a national WRP provider — there is no self-signed variant. The profile adds basicConstraints{cA=false}, keyUsage{digitalSignature} (both critical), and a subject key identifier; unlike the Provider profiles, certificatePolicies and qcStatements are not added automatically and must be supplied in the request.
Endpoint: POST /v1/{target}/x509-service-api/certificates | API Reference
Example Request
curl -X 'POST' \
'https://{orgID}.enterprise-sandbox.waltid.dev/v1/{target}/x509-service-api/certificates' \
-H 'accept: application/json' \
-H 'Authorization: Bearer {yourToken}' \
-H 'Content-Type: application/json' \
-d '{
"certificateProfile": "etsi-wrpac",
"issuerCertificateRef": "test.tenant1.x509-store-1.wrp-national-provider",
"subjectKeyRef": "test.tenant1.kms1.wrp-key",
"subjectDn": "CN=Example Relying Party,O=Example Relying Party AT,C=AT",
"validFrom": "2026-09-01T00:00:00Z",
"validTo": "2027-09-01T00:00:00Z",
"certificatePolicyOids": ["0.4.0.194118.1.2"],
"subjectAlternativeNames": [
{ "type": "uri", "name": "https://relying-party.example.com" }
],
"crlDistributionPointUri": "https://crl.example.com/wrpac.crl",
"authorityInfoAccessCaIssuerUris": ["https://ca.example.com/wrp-national-provider.crt"]
}'
Body Parameters
certificateProfile: String (required here) -etsi-wrpac.issuerCertificateRef/issuerCertificatePem: String (required) - The issuing national WRP provider certificate.certificatePolicyOids: Array of Strings (required by profile) - Exactly one WRPAC policy OID (ETSI TS 119 411-8 clause 5.3):0.4.0.194118.1.1(NCP natural person),0.4.0.194118.1.2(NCP legal person),0.4.0.194118.1.3(QCP natural person),0.4.0.194118.1.4(QCP legal person).qcStatements: Object (required if the policy OID above is a QCP one) - SetqcCompliance: trueandqcSscd: true; for the legal-person QCP OID also setqcTypeOids(any non-empty QcType statement). Not required, and normally omitted, for the NCP policy OIDs.subjectAlternativeNames: Array (required by profile) - At least oneurioremailentry carrying Relying Party contact information.crlDistributionPointUriand/orauthorityInfoAccessOcspResponderUris: String / Array of Strings (required by profile) - At least one revocation mechanism (CRL or OCSP).authorityInfoAccessCaIssuerUris/authorityInfoAccessOcspResponderUris: Array of Strings (required by profile) - WRPAC is always CA-issued, soauthorityInfoAccessis mandatory.
Response Codes
200/201- Certificate issued (persisted when a store is attached).400- Profile validation failed (e.g. missing or non-unique WRPAC policy OID, missing contact SAN, no revocation mechanism, missingqcStatementsfor a QCP policy, malformed DN).401- Invalid or missing authentication token.500- The certificate was generated but a required store write failed. CheckpersistResultfor which store reportedFAILED; safe to retry with the same request.
ETSI Wallet Relying Party Registration Certificate (WRPRC)
Set certificateProfile to etsi-wrprc. Issues an end-entity certificate that registers a Relying Party with a national registrar, per ETSI TS 119 475. Always CA-issued by a national registrar — there is no self-signed variant. The profile adds the same baseline extensions as WRPAC (basicConstraints{cA=false}, keyUsage{digitalSignature}, subject key identifier); certificatePolicyOids and authorityInfoAccess must be supplied in the request, and the subject DN is always treated as a legal person.
etsi-wrprc is a draft profile — it does not yet validate the WRPRC-specific "registered intended use" (the scope a registrar authorizes the Relying Party to request). See Certificate profiles.
Endpoint: POST /v1/{target}/x509-service-api/certificates | API Reference
Example Request
curl -X 'POST' \
'https://{orgID}.enterprise-sandbox.waltid.dev/v1/{target}/x509-service-api/certificates' \
-H 'accept: application/json' \
-H 'Authorization: Bearer {yourToken}' \
-H 'Content-Type: application/json' \
-d '{
"certificateProfile": "etsi-wrprc",
"issuerCertificateRef": "test.tenant1.x509-store-1.wrp-national-provider",
"subjectKeyRef": "test.tenant1.kms1.wrp-registration-key",
"subjectDn": "CN=Example Relying Party,O=Example Relying Party AT,C=AT",
"validFrom": "2026-09-01T00:00:00Z",
"validTo": "2027-09-01T00:00:00Z",
"certificatePolicyOids": ["1.3.6.1.4.1.55555.3.1"],
"authorityInfoAccessCaIssuerUris": ["https://ca.example.com/wrp-national-provider.crt"]
}'
Body Parameters
certificateProfile: String (required here) -etsi-wrprc.issuerCertificateRef/issuerCertificatePem: String (required) - The issuing national registrar certificate.subjectDn: String (required unlesscsrPemis used) - Legal-person DN: requiresC=,CN=, andO=.certificatePolicyOids: Array of Strings (required by profile) - At least one policy OID; ETSI TS 119 475 does not yet define a fixed WRPRC OID, so use whatever the issuing registrar's CPS defines.authorityInfoAccessCaIssuerUris/authorityInfoAccessOcspResponderUris: Array of Strings (required by profile) - WRPRC is always CA-issued, soauthorityInfoAccessis mandatory.
Response Codes
200/201- Certificate issued (persisted when a store is attached).400- Profile validation failed (e.g. missing certificate policy OID, missingauthorityInfoAccess, malformed DN).401- Invalid or missing authentication token.500- The certificate was generated but a required store write failed. CheckpersistResultfor which store reportedFAILED; safe to retry with the same request.
Issue or replace a certificate (PUT)
PUT /certificates writes the certificate at the ID given in the path, creating it if it does not exist and updating it if it does.
PUT /certificates requires at least one attached X.509 Store service — there is nowhere to upsert a certificate without one. Use POST /certificates for stateless issuance.
Endpoint: PUT /v1/{target}/x509-service-api/certificates | API Reference
Example Request
curl -X 'PUT' \
'https://{orgID}.enterprise-sandbox.waltid.dev/v1/{target}.leaf-service-a/x509-service-api/certificates' \
-H 'accept: application/json' \
-H 'Authorization: Bearer {yourToken}' \
-H 'Content-Type: application/json' \
-d '{
"issuerCertificateRef": "test.tenant1.x509-store-1.example-root-ca",
"subjectKeyRef": "test.tenant1.kms1.leaf-key",
"subjectDn": "CN=Service A,O=Example Org,C=US",
"validFrom": "2026-09-01T00:00:00Z",
"validTo": "2027-09-01T00:00:00Z",
"keyUsage": ["digitalSignature"],
"upsertStrategy": "UPSERT_ALL"
}'
Path Parameters
target: resourceIdentifier (required) - Must include the certificate ID:{organizationID}.{tenantID}.{x509ServiceID}.{certificateID}.
Body Parameters
- Same as
POST /certificates, withupsertStrategyinstead ofcreateStrategy.
Response Codes
200- Existing certificate replaced.201- Certificate created.400- Invalid request.401- Invalid or missing authentication token.500- The certificate was generated but a required store write failed. CheckpersistResultfor which store reportedFAILED; safe to retry with the same request.
Response model
Both endpoints return an UpsertCertificateResponse:
certificate: Object - The issued certificate._id: String - Full path. When a store is attached this is{store}.{certificateID}; otherwise{x509ServiceID}.{certificateID}.certificatePem: String - PEM-encoded certificate.issuerDn/issuerDnHex,subjectDn/subjectDnHex: String - Distinguished names in string and hex-DER form.validFrom/validTo: String - Effective validity window (truncated to whole seconds).metadata: Object - Stored metadata, including the resolvedissuerKeyRef,subjectKeyRef,issuerCertRef, and anyvicalDocTypeyou supplied.createdAt/updatedAt: String - Persistence timestamps.
persistResult: Object - Maps each full stored certificate path to its outcome:CREATED,UPDATED,ALREADY_EXISTS, orFAILED. Empty when no store is attached.
Store persistence
The service's default persistence strategy (set at Setup) decides which attached stores receive the certificate and when the request counts as successful. Any request can override it:
upsertStrategy(PUT) — how the write certificates across stores.successStrategy—ANY_OKorALL_OK.storeRef— restrict the write to one named store.
With successStrategy: ANY_OK a partial failure still returns success as long as at least one store write succeeds; inspect persistResult for per-store FAILED entries. If every write fails (ANY_OK), or any write fails (ALL_OK), the request returns 500 even though the certificate was generated — the FAILED entries in persistResult say which store(s) rejected the write.
Deprecated endpoints
The following endpoints and request shapes are still served for backward compatibility but are superseded by POST / PUT /certificates:
| Deprecated | Replacement |
|---|---|
POST /x509-service-api/certificate (generic, key-descriptor / issuer objects) | POST /x509-service-api/certificates with flat subjectKeyRef / issuerKeyRef / issuer fields |
POST /x509-service-api/iso/iacas | POST /x509-service-api/certificates with certificateProfile: "iso-iaca-root", selfSigned: true |
POST /x509-service-api/iso/document-signers | POST /x509-service-api/certificates with certificateProfile: "iso-document-signer" |
POST /x509-service-api/csrs with type: "generic" / type: "iso-document-signer" and subjectKeyDescriptor | POST /x509-service-api/csrs with flat subjectKeyRef / subjectKeyJwk and subjectDn — see CSR Workflows |
New integrations should not use the deprecated endpoints. They accept the old kms-hosted-key-descriptor / jwk-encoded-key-descriptor objects and the old storedCertificateId body field, none of which exist on POST / PUT /certificates.
