Skip to main content

Handling Transaction Data in Requests

Some proof requests carry transaction data alongside the credential request itself. This is represented by transaction_data in OpenID4VP and carries additional information the wallet holder should review and approve before presenting a credential.

Overview

When a request includes transaction data, Procivis One surfaces it to the holder for review before any credential is shared. If the holder approves, that approval is cryptographically bound to the credential presentation, so the verifier can confirm both that a valid credential was presented and that the holder specifically reviewed and approved this exact transaction. See Requesting Authorization for Transactions for the verifier side of this flow.

This document describes what Procivis One does with transaction data end-to-end, including rendering it in the Business (server) and mobile wallets. If you are building your own wallet against Core's APIs, the same sequence applies.

Prerequisites

transactionDataProvider must be configured. Each provider type enables one particular kind of transaction data. See Configuring OpenID4VP for wallets - Transaction data.

Receiving transaction data

info

REST: POST /api/interaction/v1/handle-invitation
Mobile: handleInvitation(request)

When an invitation contains a transaction_data query parameter, Procivis One decodes it and stores each entry as part of the interaction. It expects type and credential_ids; transaction_data_hashes_alg is optional.

At this point, Procivis One validates the request and fails the invitation immediately if any of the following don't hold:

  • type must reference a configured transactionDataProvider.
  • Every ID in a transaction data entry's credential_ids must match a credential query ID in the accompanying DCQL query.
  • Each of those referenced credential queries must have require_cryptographic_holder_binding set to true; transaction data can only be requested against credentials capable of a holder-binding proof.

A single transaction data entry can reference multiple credential queries, binding the same approval across more than one credential.

Discovering what's requested

info

REST: GET /api/proof-request/v2/{id}/presentation-definition
Mobile: getPresentationDefinitionV2(proofId)

Alongside the usual credential queries, the presentation definition includes a summary of any transaction data attached to the request:

"transactionData": [
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"type": "QES_APPROVAL",
"credentialQueryIds": ["identity_card"]
}
]
  • id — identifies this transaction data entry. Use it as transactionDataId in the next call.
  • type — the transaction data provider name.
  • credentialQueryIds — which of the request's credential queries this entry applies to.

Fetching full transaction data detail

info

REST: GET /api/proof-request/v1/{proofId}/transaction-data/{transactionDataId}
Mobile: holderGetTransactionData(proofId, transactionDataId)

Returns the full detail for a single transaction data entry, including data formatted for display:

{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"type": "QES_APPROVAL",
"credentialQueryIds": ["identity_card"],
"transactionDataDisplay": [
{
"title": "Example Contract",
"attributes": [
{ "key": "transactionData.qesApproval.documentInfo.href", "value": "https://..." }
]
}
],
"rawTransactionData": { "...": "..." }
}
  • transactionDataDisplay — grouped, human-readable key-value data for presenting the transaction to the holder. Whether this is present depends on the transactionDataProvider configuration: it's populated only if the provider is configured with transactionDataDisplayParams (see Transaction data providers for groupPath/titlePath/attributes configuration). It's optional from the wallet's perspective, but providing it is what lets a wallet UI render the transaction without needing to understand each type's raw payload.
  • rawTransactionData — the full, provider-specific transaction data as received from the verifier, useful for a "details" or "advanced" view. On mobile, this is returned as a JSON-encoded string rather than a native object — over REST it's a JSON object embedded directly.

Submitting approval

info

REST: POST /api/interaction/v2/presentation-submit
Mobile: holderSubmitProofV2(interactionId, submission)

{
"interactionId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"submission": {
"identity_card": [
{
"credentialId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"userSelections": [],
"transactionDataIds": []
}
]
}
}

submission is keyed by credential query id (identity_card above is a placeholder for whichever query id the credential satisfies), each mapping to the credential(s) submitted for that query.

  • userSelections — unrelated to transaction data; this is where the holder opts in to sharing optional claims.
  • transactionDataIds — which transaction data entries (by the id from the previous step) this credential's presentation should bind to. In most cases you can omit this or pass an empty array: entries not explicitly listed anywhere are auto-assigned to an applicable credential automatically. Set it explicitly only when a request has multiple credentials or multiple transaction data entries and you need to control which credential binds to which entry.

On approval, Procivis One computes the appropriate binding for the credential's format and includes it in the presentation.

After submission

Once the presentation is submitted, the wallet's role in this exchange is complete. The verifier is responsible for validating the presentation and for anything that follows from the transaction being approved. See Requesting Authorization for Transactions for Procivis One's implementation of that side of the flow.