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
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:
typemust reference a configuredtransactionDataProvider.- Every ID in a transaction data entry's
credential_idsmust match a credential query ID in the accompanying DCQL query. - Each of those referenced credential queries must have
require_cryptographic_holder_bindingset totrue; 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
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 astransactionDataIdin 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
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 thetransactionDataProviderconfiguration: it's populated only if the provider is configured withtransactionDataDisplayParams(see Transaction data providers forgroupPath/titlePath/attributesconfiguration). 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
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 theidfrom 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.