This joint use case between Docusign and JPMorgan Chase demonstrates how financial institutions can modernize the account opening experience by combining workflow orchestration, identity validation, and agreement execution into a single, streamlined process.
The solution uses Docusign Maestro to orchestrate the end-to-end workflow and integrates with JPMorgan validation services to perform entity and account verification. Docusign Data IO securely exchanges data between systems, enabling real-time validation and reducing manual intervention.
Together, these components create a compliant, automated account opening flow that accelerates onboarding, improves data accuracy, and delivers a seamless customer experience.
These verification endpoints from JPMorgan are used:
This reference implementation supports two authentication flows:
- Authorization Code Grant – required for public extension apps
- Client Credentials Grant – available to private extension apps. See Choosing private distribution instead of public.
Private extension apps can use either authentication method, but public extension apps must use Authorization Code Grant.
You can use the hosted version of this reference implementation by directly uploading the appropriate manifest file located in the /manifests folder to the Docusign Developer Console. See Upload your manifest.
Note: The provided manifest includes clientId and clientSecret values used in the sample authentication connection. These do not authenticate to a real system, but the hosted reference implementation requires these exact values.
If you want to run the app locally using Node.js and ngrok, follow the Local setup instructions below.
Run the following command to clone the repository:
git clone https://github.com/docusign/automated-account-opening-implementation.gitIf you already have values for JWT_SECRET_KEY, OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET, and AUTHORIZATION_CODE, you may skip this step.
The easiest way to generate a secret value is to run the following command:
node -e "console.log(require('crypto').randomBytes(64).toString('hex'));"You will need values for JWT_SECRET_KEY, OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET, and AUTHORIZATION_CODE.
- If you're running this in a development environment, create a copy of
example.development.envand save it asdevelopment.env. - If you're running this in a production environment, create a copy of
example.production.envand save it asproduction.env. - Replace
JWT_SECRET_KEY,OAUTH_CLIENT_ID,OAUTH_CLIENT_SECRET, andAUTHORIZATION_CODEindevelopment.envorproduction.envwith your generated values. These values will be used to configure the sample proxy's mock authentication server. - Replace
JPM_CLIENT_IDandJPM_SECRET_KEYindevelopment.envorproduction.envwith your keys from JPMorgan account. These values will be used to authorize in JPMorgan and retrieve the access token.
Run the following command to install the necessary dependencies:
npm installStart the proxy server in development mode by running
npm run devThis will create a local server on the port in the development.env file (port 3000 by default) that listens for local changes that trigger a rebuild.
Start the proxy server in production mode by running
npm run build
npm run startThis will start a production build on the port in the production.env file (port 3000 by default).
Run the following command to create a publicly accessible tunnel to your localhost:
ngrok http <PORT>Replace <PORT> with the port number in the development.env or production.env file.
Copy the Forwarding address from the response. You’ll need this address in your manifest.json file.
ngrok
Send your ngrok traffic logs to Datadog: https://ngrok.com/blog-post/datadog-log
Session Status online
Account email@domain.com (Plan: Free)
Update update available (version 3.3.1, Ctrl-U to update)
Version 3.3.0
Region United States (us)
Latency 60ms
Web Interface http://127.0.0.1:4040
Forwarding https://bbd7-12-202-171-35.ngrok-free.app -> http:
Connections ttl opn rt1 rt5 p50 p90
0 0 0.00 0.00 0.00 0.00In this example, the Forwarding address to copy is https://bbd7-12-202-171-35.ngrok-free.app.
Choose a manifest from the manifests folder based on the appropriate authentication use case. Replace <PROXY_BASE_URL> in your manifest.json file with the ngrok forwarding address in the following sections:
connections.params.customConfig.tokenUrlconnections.params.customConfig.authorizationUrlactions.params.uri
Update the following variables in your manifest.json file with the corresponding environment variables:
- Set the
CLIENT_IDvalue in your manifest.json file to the same value asOAUTH_CLIENT_ID. - Set the
CLIENT_SECRETvalue in your manifest.json file to the same value asOAUTH_CLIENT_SECRET.
2. Navigate to the Docusign Developer Console
Log in with your Docusign developer credentials.
Register your extension app by uploading your app manifest.
Test your extension app. Extension app tests include integration tests (connection tests and extension tests), functional tests, and App Center preview.
For the data search records extensions, this implementation uses the JP Morgan entity and account verifications to check the data. Test your extension using the sample data below:
-
DataIO.Version6.SearchRecords: This action will send the data that identifies entity and account and checks them using JPMorgan API.Example JSON request body:
{ "query": { "$class": "com.docusign.connected.data.queries@1.0.0.Query", "attributesToSelect": [ "verified", "verificationHeader", "verificationMessage" ], "from": "Entity", "queryFilter": { "$class": "com.docusign.connected.data.queries@1.0.0.QueryFilter", "operation": { "$class": "com.docusign.connected.data.queries@1.0.0.LogicalOperation", "leftOperation": { "$class": "com.docusign.connected.data.queries@1.0.0.ComparisonOperation", "leftOperand": { "$class": "com.docusign.connected.data.queries@1.0.0.Operand", "name": "firstName", "type": "STRING", "isLiteral": false }, "operator": "EQUALS", "rightOperand": { "$class": "com.docusign.connected.data.queries@1.0.0.Operand", "name": "John", "type": "STRING", "isLiteral": true } }, "operator": "AND", "rightOperation": { "$class": "com.docusign.connected.data.queries@1.0.0.LogicalOperation", "leftOperation": { "$class": "com.docusign.connected.data.queries@1.0.0.ComparisonOperation", "leftOperand": { "$class": "com.docusign.connected.data.queries@1.0.0.Operand", "name": "lastName", "type": "STRING", "isLiteral": false }, "operator": "EQUALS", "rightOperand": { "$class": "com.docusign.connected.data.queries@1.0.0.Operand", "name": "Doe", "type": "STRING", "isLiteral": true } }, "operator": "AND", "rightOperation": { "$class": "com.docusign.connected.data.queries@1.0.0.LogicalOperation", "leftOperation": { "$class": "com.docusign.connected.data.queries@1.0.0.ComparisonOperation", "leftOperand": { "$class": "com.docusign.connected.data.queries@1.0.0.Operand", "name": "fullName", "type": "STRING", "isLiteral": false }, "operator": "EQUALS", "rightOperand": { "$class": "com.docusign.connected.data.queries@1.0.0.Operand", "name": "John Doe", "type": "STRING", "isLiteral": true } }, "operator": "AND", "rightOperation": { "$class": "com.docusign.connected.data.queries@1.0.0.LogicalOperation", "leftOperation": { "$class": "com.docusign.connected.data.queries@1.0.0.ComparisonOperation", "leftOperand": { "$class": "com.docusign.connected.data.queries@1.0.0.Operand", "name": "addressLine", "type": "STRING", "isLiteral": false }, "operator": "EQUALS", "rightOperand": { "$class": "com.docusign.connected.data.queries@1.0.0.Operand", "name": "New York, Shevchenka St., 1", "type": "STRING", "isLiteral": true } }, "operator": "AND", "rightOperation": { "$class": "com.docusign.connected.data.queries@1.0.0.LogicalOperation", "leftOperation": { "$class": "com.docusign.connected.data.queries@1.0.0.ComparisonOperation", "leftOperand": { "$class": "com.docusign.connected.data.queries@1.0.0.Operand", "name": "country", "type": "STRING", "isLiteral": false }, "operator": "EQUALS", "rightOperand": { "$class": "com.docusign.connected.data.queries@1.0.0.Operand", "name": "US", "type": "STRING", "isLiteral": true } }, "operator": "AND", "rightOperation": { "$class": "com.docusign.connected.data.queries@1.0.0.LogicalOperation", "leftOperation": { "$class": "com.docusign.connected.data.queries@1.0.0.ComparisonOperation", "leftOperand": { "$class": "com.docusign.connected.data.queries@1.0.0.Operand", "name": "townName", "type": "STRING", "isLiteral": false }, "operator": "EQUALS", "rightOperand": { "$class": "com.docusign.connected.data.queries@1.0.0.Operand", "name": "New York", "type": "STRING", "isLiteral": true } }, "operator": "AND", "rightOperation": { "$class": "com.docusign.connected.data.queries@1.0.0.LogicalOperation", "leftOperation": { "$class": "com.docusign.connected.data.queries@1.0.0.ComparisonOperation", "leftOperand": { "$class": "com.docusign.connected.data.queries@1.0.0.Operand", "name": "dateOfBirth", "type": "STRING", "isLiteral": false }, "operator": "EQUALS", "rightOperand": { "$class": "com.docusign.connected.data.queries@1.0.0.Operand", "name": "2000/03/01", "type": "STRING", "isLiteral": true } }, "operator": "AND", "rightOperation": { "$class": "com.docusign.connected.data.queries@1.0.0.LogicalOperation", "leftOperation": { "$class": "com.docusign.connected.data.queries@1.0.0.ComparisonOperation", "leftOperand": { "$class": "com.docusign.connected.data.queries@1.0.0.Operand", "name": "id", "type": "STRING", "isLiteral": false }, "operator": "EQUALS", "rightOperand": { "$class": "com.docusign.connected.data.queries@1.0.0.Operand", "name": "111223333", "type": "STRING", "isLiteral": true } }, "operator": "AND", "rightOperation": { "$class": "com.docusign.connected.data.queries@1.0.0.LogicalOperation", "leftOperation": { "$class": "com.docusign.connected.data.queries@1.0.0.ComparisonOperation", "leftOperand": { "$class": "com.docusign.connected.data.queries@1.0.0.Operand", "name": "idType", "type": "STRING", "isLiteral": false }, "operator": "EQUALS", "rightOperand": { "$class": "com.docusign.connected.data.queries@1.0.0.Operand", "name": "SSN", "type": "STRING", "isLiteral": true } }, "operator": "AND", "rightOperation": { "$class": "com.docusign.connected.data.queries@1.0.0.ComparisonOperation", "leftOperand": { "$class": "com.docusign.connected.data.queries@1.0.0.Operand", "name": "email", "type": "STRING", "isLiteral": false }, "operator": "EQUALS", "rightOperand": { "$class": "com.docusign.connected.data.queries@1.0.0.Operand", "name": "john.doe@example.com", "type": "STRING", "isLiteral": true } } } } } } } } } } } } }, "pagination": { "limit": 10, "skip": 10 } }Example JSON response:
{ "records": [ { "verified": true, "message": "Successful verification" } ] }
Common issues:
ngrok URL changed → update manifest.json
401 from JPMorgan API → check JPM_CLIENT_ID and JPM_SECRET_KEY
Connection test failed in DocuSign → verify proxy server is running