Developer Docs
Sandbox · API v2PlaygroundGet API keys

Passports & versions

A Passport (DPP) is a versioned product-information artifact with defined disclosure and lifecycle. It is generated from a product, then published, and once published, a version is never mutated, only superseded.

States, three vocabularies, do not conflate

  • Product DPP-journey status (the canonical 11-state vocabulary, what generation drives): draft → validated → ready_for_dpp → dpp_pending → dpp_issued → published, plus the terminal/exception states suspended, expired, withdrawn, recalled, recycled (and voided for serialized-item tombstones).
  • Passport command-machine state (what passport commands drive): draft | submitted | rejected | approved | published | suspended | revoked | archived | recycled. A draft is publicly indistinguishable from nonexistent (404 "not found or not published").
  • EU Registry status (per passport): NOT_REQUIRED | PENDING | REGISTERED | FAILED | SYNCED | REVOKED, the passport's standing against the ESPR Art. 13 EU registry, independent of lifecycle state.

"Superseded" is not a lifecycle state, it is the version-level attribute of v(N) after a republish mints v(N+1).

Immutable versioning

Every publish mints an immutable passport_version: version number, a previous_version_id hash-chain link, and a current flag. Republishing mints v(N+1); v(N) is superseded, never edited. Read the chain at GET /passports/{id}/history.

Temporal as-of queries are live: GET /passports/{id}/as-of?date=<ISO 8601> returns the passport projection that was valid at the given instant, a pre-update timestamp returns the old value, a post-update timestamp the new one. A date before the first version returns a typed 404 NOT_FOUND ("No passport version was active at …").

Publishing

Publishing needs an eIDAS actor identity bound to the person or system that publishes. Norruva cannot bind one yet. So in production every route in this section answers 503 EIDAS_ACTOR_BINDING_UNAVAILABLE, except registerDPP, which answers 501 (see below). Nothing is published, registered, broadcast or issued, and you can retry the same request once binding is available. Outside production, publishing proceeds so you can build and test your integration. The credential routes are different: they answer 503 in every environment.

These routes have distinct jobs. Do not conflate them:

POST/api/v2/passports/commands · PASSPORT.PUBLISHpublishes a passport through its lifecycle

The lifecycle command for an approved passport. It needs an evidenceBundleRef, the passport in the approved state, the products:edit scope on your key, and the publishing user's products:publish permission. In production it answers 503 EIDAS_ACTOR_BINDING_UNAVAILABLE in the standard error envelope, and the passport stays approved and unpublished. The same 503 answers REVOKE, SUSPEND, REINSTATE and ARCHIVE, and RECYCLE of a passport that has ever been published.

POST/api/v2/products/{productId}/publish-dppregisters the Digital Link

Makes the product resolvable through its Digital Link and, outside production, returns the public passportUid, the verifiable credential and a merkleRoot. In production it answers 503 EIDAS_ACTOR_BINDING_UNAVAILABLE in the standard error envelope: nothing is published or anchored, and no credential is issued. A battery product answers 503 COMPLIANCE_EVALUATION_UNAVAILABLE while battery evaluation is switched off.

POST/api/v2/dpp/{productId}/publishmints passport content

Mints the public passport content from the product's current data. In production it answers 503 with a flat body, { "error": "...", "code": "EIDAS_ACTOR_BINDING_UNAVAILABLE" }, not the standard error envelope: read code, not error.code. No passport content is minted.

POST/api/v2/passports/{id}/publishbroadcasts to external registries (Catena-X, GS1, EBSI; optional)

Sends an already published passport to external registries. It does not publish the passport. In production it answers 503 EIDAS_ACTOR_BINDING_UNAVAILABLE in the standard error envelope and no registry is called. Outside production, a 503 without that code means no registry accepted the broadcast.

POST/api/v2/dpp/generategenerates passport data from a product

Generates passport data for a product. A malformed body answers 400 first, because the body is checked before anything else. A valid body in production answers 503 EIDAS_ACTOR_BINDING_UNAVAILABLE, and nothing is generated.

POST/api/v2/registerDPP (and /api/v1/registerDPP)submits a passport to the registry (EN 18222 operation)

The EN 18222 register operation. Registration is not supported until an eIDAS actor identity can be bound, so in production this route answers 501 with no body. The reason is in the X-Norruva-Error-Code response header: EIDAS_ACTOR_BINDING_UNAVAILABLE. Nothing is submitted. Do not retry automatically: the same request will get the same answer until binding exists.

POST/api/v2/credentials/issueissues a verifiable credential

Answers 503 in every environment: "Credential issuance is unavailable until a resolvable actor identity can be bound." No credential is issued.

POST/api/v2/credentials/commandscredential lifecycle commands

Answers 503 in every environment with a flat body, { "success": false, "errorCode": "EIDAS_ACTOR_BINDING_UNAVAILABLE", "errorMessage": "..." }, and the same code in the X-Norruva-Error-Code header. No credential changes state.

Lifecycle guards

Guards are real: an EDIT on a published passport returns 403 GUARD_REJECTED. Replaying a command with the same idempotencyKey returns the first result. See Passport commands.

Was this page helpful?
Thanks, noted.Feedback goes to the docs team by email.