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"),
vaultProfile = employeeVaultProfile,
governance = employeeGovernance,
),
),
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 an OCA capture bundle 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.

Configure deferred issuance in the credential binding as well as the connector's execution policy. An asynchronous connector setting alone is not a substitute for the credential's deferral and approval gates. See callback ingress for the inbound, token-authorized contribution interface.

Failure, Retry, and Delivery Outcomes​

Choose the failure policy independently from the protocol stage. For example, failure to retrieve a required employment claim should prevent issuance, whereas a downstream notification may use a separately monitored delivery path.

failureEffectEffect when an inline invocation fails
FAIL_PROTOCOLReturn the invocation error to the calling protocol integration
RETRY_ONLYAlso return the error for inline execution; this value alone does not schedule a durable retry
CONTINUE_WITHOUT_EFFECTContinue with a FAILED_CONTINUED result and no successful integration effect
DEAD_LETTERReturn a DEAD_LETTERED dispatch result
QUARANTINEReturn a QUARANTINED dispatch result

For durable retry, dead-letter storage, and operator replay, use the VDX-backed connector execution services. A dispatch result and a persisted dead-letter record are different things: check the run, its events, and the stored failure record before initiating recovery. Keep the invocation binding id, protocol correlation id, run id, and event cursor together so a delivery can be traced back to its issuance session. A successful HTTP submission is not proof of a successful sink commit.

Replay is an authorized recovery operation, not a new issuance request. Record the reason, verify the recovered run and destination effect, and handle duplicate delivery idempotently. Do not issue a second credential just to retry an unrelated downstream notification.

For presentation integrations, OID4VP_AFTER_VALIDATION bindings run only for a valid presentation. Their selected fields and delivery results are separate from the verifier's status callback. A delivery failure must not be interpreted as a new cryptographic assessment of the presented credential. See the OID4VP integration guide for session creation, status retrieval, and result handling.

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.

A VAULT_RETENTION binding must provide both vaultProfile and governance. In the pipeline example, employeeVaultProfile and employeeGovernance represent your configured retention destination and governance policy. Missing or invalid vault governance fails before execution, even when the binding would otherwise continue after an operational delivery failure.

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.