Skip to main content
Version: 1.0.0

Verifiable Credentials

Verifiable Credentials (VCs) are secure digital credentials that allow users to share their financial data while maintaining control over their privacy.

In UCW, VCs combine the FDX Data Standard with VCs to:

  • Allow users to securely prove facts without revealing their entire identity
  • Provide tamper-evident data that can be verified without contacting the original issuer
  • Enable complete user control over data sharing
Prerequisite

These endpoints are disabled by default. See Enable UCW Data Endpoints.

For technical details, see W3C's Verifiable Credentials Data Model.

Strategic Advantage

Regulators increasingly favor VCs as they enhance user privacy and control. Implementing VCs now gives your application a competitive advantage in the evolving regulatory landscape.

Aggregator Support

info

Not all aggregators support VCs. Check the table below and refer to specific documentation:

AggregatorConnectionData
Endpoints
VC
Endpoints
Akoya
Finicity
MX
Sophtron

Supported functionality by aggregator

How UCW Uses VCs

  1. The aggregator formats user data (accounts, transactions, identity) according to FDX standards
  2. The aggregator signs this data with their private key and packages it as a Verifiable Credential
  3. Your application requests this data from UCW, which returns it as a JWT
  4. You verify the JWT using the aggregator's decentralized identifier (DID)
  5. After you decode the JWT, you use the standardized data in your application
Report Inconsistencies

We strive for consistency in data formats across aggregators. Please report any discrepancies you encounter.

Decentralized Identifiers (DIDs)

Each aggregator has a unique DID for verification:

  • MX: did:dht:kfcakjzahwimgo9zzjw6yknt9srdtkmfqbeybekcg3xzz1ztg95y
  • Sophtron: did:ion:EiDPbz2t9aw5u8GRCRyyY090Gk3vSHmsZFLYgVnBurOMEw

Using VC Endpoints

This section describes how to use the Verifiable Credential (VC) endpoints that retrieve data in an FDX format. If you'd like to use data endpoints instead, see UCW Data Endpoints.

Before making any VC requests, you must first listen for the postMessage when a user connects an account.

warning

The userId in your data requests must match the userId configured in the widget.

Common Implementation Steps

  1. Configure appropriate jobtypes in your widget URL to ensure necessary data is collected
  2. Extract the member_guid from the widget's postMessage event
  3. Make API requests to the appropriate VC endpoint
  4. Verify and decode the returned JWT
  5. Process the standardized FDX data

Account data

To retrieve account data:

  1. Define your jobtypes in the widget URL. Only data that is aggregated for the defined job is assigned to the VC.
  2. Capture the member_guid in the postmessage event and use it as the connectionId in the VC request.
  3. In the VC request, also set the aggregator and userId.
  4. Use a decoding option of your choice to decode the JWT and read the account data.

Example Request

curl -i -X GET 'https://your-widget-url.com/api/vc/data/aggregator/{aggregator}/user/{userId}/connection/{connectionId}/accounts' \
-H 'Accept: your header here' \
-H 'Content-Type: application/json' \

Example Response

{
jwt: "vcToken"
}
Example Account Data
{
"vc": {
"@context": [
"https://www.w3.org/2018/credentials/v1"
],
"id": "https://api.test.test.mx/vc/users/USR-3ea736e24-edd6-4417-9b5-dee48cc3125b/members/MBR-c4985cbf-63d9-145f-87272-e4e41ccf3b6/accounts",
"type": [
"VerifiableCredential",
"FinancialAccountCredential"
],
"issuer": "did:dht:sa7cseh7jcz51wj6fj13dw7jyg44ejwcdf8iqxbooj41ipeg76eo",
"issuanceDate": "2024-03-01T18:42:19Z",
"credentialSubject": {
"accounts": [
{
"locAccount": {
"accountId": "ACT-848-57d0-4a24-a0c1-e72ad24a0126096bd",
"accountType": "CREDITCARD",
"accountNumber": "324453974",
"accountNumberDisplay": "****5344",
"productName": null,
"nickname": null,
"status": "OPEN",
"accountOpenDate": "2022-07-11T15:40:40Z",
"accountClosedDate": null,
"currency": {
"currencyRate": null,
"currencyCode": null,
"originalCurrencyCode": null
},
"fiAttributes": [
{
"name": "member_guid",
"value": "MBR-f1a3285d-63d9-498f-8772-8ae775c0e0e9"
},
{
"name": "institution_guid",
"value": "INS-f7e87eff-e855-b68f-68a7-e5192784ccb6"
},
{
"name": "external_guid",
"value": "account-cc5145bf-06c0-46a1-b800-3ef3241621a9"
}
],
"routingTransitNumber": null,
"balanceType": "LIABILITY",
"interestRate": null,
"lastActivityDate": "2022-07-11T15:40:40Z",
"balanceAsOf": "2022-07-11T15:40:40Z",
"creditLine": null,
"availableCredit": 13000,
"nextPaymentDate": null,
"principalBalance": null,
"currentBalance": 1000,
"minimumPaymentAmount": null,
"purchasesApr": null
}
},
{
"depositAccount": {
"accountId": "ACT-96f3fdas3-1e05-4a4b-9fd5-571f32fdad95c",
"accountType": "CHECKING",
"accountNumber": "898735161",
"accountNumberDisplay": "****5161",
"productName": null,
"nickname": null,
"status": "OPEN",
"accountOpenDate": "2022-07-11T15:40:40Z",
"accountClosedDate": null,
"currency": {
"currencyRate": null,
"currencyCode": null,
"originalCurrencyCode": null
},
"fiAttributes": [
{
"name": "member_guid",
"value": "MBR-cc5dsa5f-63d9-498f-8772-e4ey9841ccb6"
},
{
"name": "institution_guid",
"value": "INS-f1r5685d-e855-p98f-6aa7-8eu8470e0e9"
},
{
"name": "external_guid",
"value": "account-c6e98564-8860-0000-9d85-650dsd8fjusfe" }
],
"routingTransitNumber": null,
"balanceType": "ASSET",
"interestRate": null,
"lastActivityDate": "2022-07-11T15:40:40Z",
"balanceAsOf": "2022-07-11T15:40:40Z",
"currentBalance": 1000,
"openingDayBalance": null,
"availableBalance": 1000,
"annualPercentageYield": null,
"maturityDate": null
}
},
],
"id": "USR-3a7cc3e1-edd6-b317-9f65-d6e84224ee5b"
}
},
"iss": "did:dht:sa713ddf8jcz51w7jbooj41iiqcseh7pegyg44ejwcwj6fjx76eo",
"iat": 1709318539,
"jti": "https://api.sand.internal.mx/vc/users/USR-3e3a7cc1-edd6-4417-9b35-48dee6e2425b/members/MBR-c4c515bf-63d9-498f-8772-e1cc4ef324b6/accounts",
"sub": "USR-3ccea731-edd6-4417-9b35-84dee6e2425b"
}

Transaction Data

To retrieve transactions data:

  1. Define your jobtypes in the widget URL. Only data that is aggregated for the defined job is assigned to the VC.
    • transactions for basic, recent history
    • transactionHistory for a set of transactions that cover a longer timeframe
  2. In the VC request, set the accountId, aggregator, and userId. accountId must have already been fetched in an account call.
  3. (Optional) Use these parameters on the VC data request:
    • startDate - ISO 8601 format (YYYY-MM-DD). defaults to 120 days ago
    • endDate - ISO 8601 format (YYYY-MM-DD). defaults to 5 days in the future
  4. Use a decoding option of your choice to decode the JWT and read the account data.

The verifiable credential is returned as a JWT in the response. The following example uses the aggregator, Sophtron, with their required date parameters.

Example Request

curl -i -X GET 'www.your-widget-url.com/api/vc/data/aggregator/{aggregator}/user/{userId}/account/{accountId}/transactions&startDate=2024-01-01&endDate=2022-01-01' \
-H 'Accept: your header here' \
-H 'Content-Type: application/json' \

Example Response

{
jwt: "vcToken"
}
Example Transaction Data
{
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://www.w3.org/2018/credentials/examples/v1"
],
"id": "/api/vc/customers/1d93d99e-e2f4-4dd0-b0d4-3bddd267b4c3/accounts/882d7648-d467-43ca-a240-13b08e8b4caf/transactions",
"type": [
"VerifiableCredential",
"BankTransactionCredential"
],
"issuer": "did:ion:EiDPbz2t9aw5u8GRCRyyY090Gk3vSHmsZFLYgVnBurOMEw",
"issuanceDate": "2023-08-13T13:49:04.025465084Z",
"credentialSubject": {
"id": "did:example:request",
"transactions": [
{
"depositeTransaction": {
"accountId": "882d7648-d467-43ca-a240-13b08e8b4caf",
"amount": 0,
"category": "Bank fee",
"description": "Sophtron Fee",
"fiAttributes": {
"accountID": "882d7648-d467-43ca-a240-13b08e8b4caf",
"customerID": "1d93d99e-e2f4-4dd0-b0d4-3bddd267b4c3"
},
"postedTimestamp": "2023-08-12T00:00:00",
"transactionId": "a353d7fd-a642-4ad8-95c0-fdf02d40f126",
"transactionTimestamp": "2023-08-12T00:00:00",
"transactionType": "Debit"
}
},
{
"depositeTransaction": {
"accountId": "882d7648-d467-43ca-a240-13b08e8b4caf",
"amount": 10,
"category": "Income",
"description": "Customer Deposit",
"fiAttributes": {
"accountID": "882d7648-d467-43ca-a240-13b08e8b4caf",
"customerID": "1d93d99e-e2f4-4dd0-b0d4-3bddd267b4c3"
},
"postedTimestamp": "2023-08-11T00:00:00",
"transactionId": "3fcb4b61-ef54-4410-afcf-2762fb518e20",
"transactionTimestamp": "2023-08-11T00:00:00",
"transactionType": "Credit"
}
}
]
},
"proof": {
"type": "JsonWebSignature2020",
"created": "2023-08-13T13:49:04Z",
"jws": "eyJhbGciOiJFUzI1NksiLCJiNjQiOmZhbHNlLCJjcml0IjpbImI2NCJdLCJraWQiOiJkaWQ6aW9uOkVpRFBiejJ0OWF3NXU4R1JDUnl5WTA5MEdrM3ZTSG1zWkZMWWdWbkJ1ck9NRXcifQ..n0ZZgjMev4IaSk7AzFV1DuPkn4TLWs8nQAEYPPex5JO57CNOeU-X39c7_FGLE-u6ycYYGyakDyRK0Q1OONjK3g",
"proofPurpose": "assertionMethod",
"verificationMethod": "did:ion:EiDPbz2t9aw5u8GRCRyyY090Gk3vSHmsZFLYgVnBurOMEw"
}
}

Identity Data

To retrieve identity data:

  1. Define your jobtypes as accountOwner in the widget URL. Only data that is aggregated for the defined job is assigned to the VC.
  2. Capture the member_guid in the postmessage event and use it as the connectionId in the VC request.
  3. In the VC request, also set the aggregator and userId.
  4. Use a decoding option of your choice to decode the JWT and read the account data.

Example Request

curl -i -X GET 'www.your-widget-url.com/api/vc/data/aggregator/{aggregator}/user/{userId}/connection/{connectionId}/identity' \
-H 'Accept: your header here' \
-H 'Content-Type: application/json' \

The verifiable credential is returned as a JWT in the response.

Example Response

{
jwt: "vcToken"
}
Example Identity Data
{
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://www.w3.org/2018/credentials/examples/v1"
],
"id": "/api/vc/customers/1d93d99e-e2f4-4dd0-b0d4-3bddd267b4c3/members/5807965e-091a-4f01-ae2a-0fea158ff931/identity",
"type": [
"VerifiableCredential",
"FinancialIdentityCredential"
],
"issuer": "did:ion:EiDPbz2t9aw5u8GRCRyyY090Gk3vSHmsZFLYgVnBurOMEw",
"issuanceDate": "2023-08-13T12:59:05.826034057Z",
"credentialSubject": {
"customer": {
"accounts": [
{
"accountId": "882d7648-d467-43ca-a240-13b08e8b4caf",
"relationship": "owner"
},
{
"accountId": "a82c4910-b3c3-4b5d-a0c3-1c7eaaa81ce9",
"relationship": "owner"
},
{
"accountId": "5085a4bf-0879-4efa-9b4d-6c792be40aef",
"relationship": "owner"
},
{
"accountId": "23f4c684-60b8-4c8f-a368-a814cf30c8ca",
"relationship": "owner"
},
{
"accountId": "80e5c437-ba51-4020-8972-aef1ed0ea173",
"relationship": "owner"
}
],
"addresses": [],
"customerId": "5807965e-091a-4f01-ae2a-0fea158ff931",
"fiAttributes": {
"customerID": "1d93d99e-e2f4-4dd0-b0d4-3bddd267b4c3"
},
"name": {},
"phone": []
},
"id": "did:example:request"
},
"proof": {
"type": "JsonWebSignature2020",
"created": "2023-08-13T12:59:05Z",
"jws": "eyJhbGciOiJFUzI1NksiLCJiNjQiOmZhbHNlLCJjcml0IjpbImI2NCJdLCJraWQiOiJkaWQ6aW9uOkVpRFBiejJ0OWF3NXU4R1JDUnl5WTA5MEdrM3ZTSG1zWkZMWWdWbkJ1ck9NRXcifQ..AtVwo0GRQf79tSwvE7HqMsBS0UlE0w1mbhLr38MPNrSOJUppro4IWUF7ALUQ9iuMI1Dpu7nGhfdjHpzu4tfOUQ",
"proofPurpose": "assertionMethod",
"verificationMethod": "did:ion:EiDPbz2t9aw5u8GRCRyyY090Gk3vSHmsZFLYgVnBurOMEw"
}
}