Skip to main content
Version: v0.25.0 (Latest)

Connector Invocations

OID4VCI issuance integrations are modeled as connector invocations. A connector invocation is a durable binding from an issuance phase to a connector target. It can fetch fields, push selected data out, write evidence to a vault, emit notifications, or start a route-backed integration run.

Pick Your Integration Shape

Your situationApproach
Your backend already has the data when it creates the offerSeed attributes or connector fields through the offer/session REST body
You want live data when the wallet requests the credentialBind an ENRICHMENT_SOURCE connector invocation at OID4VCI_CREDENTIAL_REQUEST
You need to resolve identity before claim enrichmentBind an enrichment invocation at OID4VCI_AUTHORIZATION or OID4VCI_TOKEN
You need final enrichment or policy state before signingBind an invocation at OID4VCI_PRE_ISSUE
You need retained evidence or re-issuance supportBind a VAULT_RETENTION invocation at OID4VCI_POST_ISSUANCE
Your upstream is slow or asynchronousUse an async/deferred execution policy and callback or deferred completion
You need audit or notificationsBind NOTIFICATION or route orchestration invocations at the relevant phase

Manual REST contributions still exist. Their contributorId field is provenance for pushed records; it is not the automatic integration binding model.

OID4VCI Phases

Connector invocation bindings can target these stages:

StageProtocol moment
OID4VCI_STARTOffer/session start before grant-specific work
OID4VCI_AUTHORIZATIONAuthorization-code flow and AS/userinfo context
OID4VCI_PRE_AUTHORIZEDPre-authorized-code offer setup
OID4VCI_TOKENToken exchange and access-token context
OID4VCI_CREDENTIAL_REQUESTWallet calls /credential
OID4VCI_PRE_ISSUEAfter request/proof validation, before the credential is built/signed
OID4VCI_DEFERREDWallet polls /credential_deferred
OID4VCI_POST_ISSUANCEAfter a credential response is produced
OID4VCI_NOTIFICATION_RECEIPTWallet sends issuance notification receipt

You do not need every phase. Bind only the phases that matter for the credential flow.

Registering an Invocation Binding

VDX-hosted deployments persist connector bindings through the connector API. This is the durable/registrable layer for connector routes, grants, throttling, run lineage, and invocation bindings; the EDK consumes the resolved connector model at issuance time.

POST /api/connector/v1/invocation/bindings
Authorization: Bearer <operator access token>
Content-Type: application/json
{
"binding": {
"invocationBindingId": "issuer-config-1:credential-request:hr-profile",
"ownerSurface": "OID4VCI",
"ownerReference": "issuer-config-1",
"stage": "OID4VCI_CREDENTIAL_REQUEST",
"role": "ENRICHMENT_SOURCE",
"target": {
"routeId": "hr-profile-route"
},
"exchangeMode": "PLATFORM_INITIATED_PULL",
"subsetMapping": {
"inputFields": [
{ "canonicalFieldPath": "employee.id" }
],
"producedFields": [
{ "canonicalFieldPath": "employee.givenName" },
{ "canonicalFieldPath": "employee.familyName" },
{ "canonicalFieldPath": "employment.department" }
]
},
"logicalContext": {
"tenantId": "tenant-1"
},
"executionPolicy": {
"timing": "INLINE_REQUIRED",
"failureEffect": "FAIL_PROTOCOL"
}
}
}

The binding id is stable and appears in audit/run lineage. The target can point at a route, connector instance, or operation binding depending on the deployment.

Composing a Pipeline

The issuer resolves a PipelineConfiguration for an issuer and requested credential configurations. The important field is invocationBindings:

val employeeCredentialPipeline = PipelineConfiguration(
pipelineId = "employee-credential-v2",
invocationBindings = listOf(
ConnectorInvocationBinding(
invocationBindingId = ConnectorInvocationBindingId("issuer-config-1:token:risk"),
ownerSurface = ConnectorOwnerSurface.OID4VCI,
ownerReference = "issuer-config-1",
stage = ConnectorInvocationStage.OID4VCI_TOKEN,
role = ConnectorInvocationRole.ENRICHMENT_SOURCE,
target = ConnectorInvocationTarget(routeId = ConnectorRouteId("risk-score-route")),
exchangeMode = ConnectorExchangeMode.PLATFORM_INITIATED_PULL,
subsetMapping = ConnectorSubsetMapping(
inputFields = listOf(ConnectorFieldSelector(protocolClaimPath = "subject")),
producedFields = listOf(ConnectorFieldSelector(canonicalFieldPath = "risk.score")),
),
logicalContext = ConnectorLogicalContext(tenantId = "tenant-1"),
),
ConnectorInvocationBinding(
invocationBindingId = ConnectorInvocationBindingId("issuer-config-1:credential-request:hr-profile"),
ownerSurface = ConnectorOwnerSurface.OID4VCI,
ownerReference = "issuer-config-1",
stage = ConnectorInvocationStage.OID4VCI_CREDENTIAL_REQUEST,
role = ConnectorInvocationRole.ENRICHMENT_SOURCE,
target = ConnectorInvocationTarget(routeId = ConnectorRouteId("hr-profile-route")),
exchangeMode = ConnectorExchangeMode.PLATFORM_INITIATED_PULL,
subsetMapping = ConnectorSubsetMapping(
inputFields = listOf(ConnectorFieldSelector(canonicalFieldPath = "employee.id")),
producedFields = listOf(
ConnectorFieldSelector(canonicalFieldPath = "employee.givenName"),
ConnectorFieldSelector(canonicalFieldPath = "employee.familyName"),
ConnectorFieldSelector(canonicalFieldPath = "employment.department"),
),
),
logicalContext = ConnectorLogicalContext(tenantId = "tenant-1"),
),
ConnectorInvocationBinding(
invocationBindingId = ConnectorInvocationBindingId("issuer-config-1:post-issuance:proof-vault"),
ownerSurface = ConnectorOwnerSurface.OID4VCI,
ownerReference = "issuer-config-1",
stage = ConnectorInvocationStage.OID4VCI_POST_ISSUANCE,
role = ConnectorInvocationRole.VAULT_RETENTION,
target = ConnectorInvocationTarget(routeId = ConnectorRouteId("proof-vault-route")),
exchangeMode = ConnectorExchangeMode.PLATFORM_INITIATED_PUSH,
logicalContext = ConnectorLogicalContext(tenantId = "tenant-1"),
),
),
claimsBindings = listOf(
CredentialClaimsBinding(
id = "EmployeeCredential",
semanticAttributeSetRef = employeeSetRef,
deferralPolicy = DeferralPolicy(enabled = false),
),
),
expectedInitialConnectorFields = setOf("employee.id"),
)

The pieces:

  • invocationBindings is the ordered connector-native contract for OID4VCI runtime integration.
  • subsetMapping.inputFields declares which connector fields, protocol claims, or canonical fields a connector needs.
  • subsetMapping.producedFields declares the canonical fields later phases can consume.
  • executionPolicy controls inline, optional, async/deferred, and durable execution.
  • claimsBindings maps each credential_configuration_id to a semantic attribute set and deferral/approval policy.
  • expectedInitialConnectorFields is the caller contract for session/offer creation.

Pattern 1: Push Known Data

If the backend already has every field when it starts issuance, push attributes or connector fields through the offer or session REST body. This is a manual contribution path. It is useful for short-lived issuance where the data is known and stable.

Use this sparingly for PII-heavy payloads. If the wallet might claim the credential much later, seed connector fields and fetch the live values through connector invocations instead.

Pattern 2: Fetch Live Data at Credential Request

For most production integrations, seed a connector field such as employee.id at offer/session start and bind an ENRICHMENT_SOURCE connector invocation at OID4VCI_CREDENTIAL_REQUEST.

When the wallet calls /credential, the EDK passes accumulated attributes and connector fields to the connector route. Returned producedFields are written back into the session bag with connector provenance, then the credential claim assembler reads them.

Pattern 3: Async or Deferred Upstream

When an upstream cannot answer within the wallet request window, set the invocation execution policy to an async or durable timing:

ConnectorInvocationExecutionPolicy(
timing = ConnectorExecutionTiming.DEFERRED_ASYNC,
failureEffect = ConnectorFailureEffect.FAIL_PROTOCOL,
syncWaitWindowMillis = 5000,
)

The EDK may wait briefly for completion. If the integration is still pending, the wallet receives a deferred credential response and polls. Callback ingress can contribute the later fields into the same session before deferred issuance completes.

Post-Issuance Retention

By default, the session retains the bag only until session expiry and cleanup. For re-issuance or audit evidence, bind OID4VCI_POST_ISSUANCE with a VAULT_RETENTION role and a materialization policy. That keeps retention explicit and tied to connector governance and run lineage.

Operational Notes

  • Use ownerSurface = OID4VCI for issuer pipeline bindings.
  • Use ownerReference consistently, usually the issuer configuration id or pipeline owner id.
  • Keep connector route execution and VDX registry state in VDX-owned modules.
  • Keep the EDK model neutral: connector/public and pipeline public contracts must not import VDX packages.
  • Manual contribution groups use contributorId only as record provenance.