Documentation Index Fetch the complete documentation index at: https://docs.emergedata.ai/llms.txt
Use this file to discover all available pages before exploring further.
Data Wallet is the end-user dashboard at https://wallet.emergedata.ai where your users can see which companies have access to their data and revoke consent at any time. This keeps consent transparent and user-controlled.
When it appears
It is created after a user completes their first successful Link consent flow.
Your user receives an email notifying them they can track their data access and revoke consent for a specific company.
What users can do
Review all connected companies and data types
See which connections are active vs revoked
Revoke consent with a single toggle
Screenshots
Handle revocations in your app
When a user revokes consent in Data Wallet, you receive a consent.revoked webhook. Use it to stop processing and delete any stored data for that user.
import express from 'express' ;
import crypto from 'crypto' ;
const app = express ();
app . use ( express . raw ({ type: 'application/json' }));
const WEBHOOK_SECRET = process . env . EMERGE_WEBHOOK_SECRET ;
if ( ! WEBHOOK_SECRET ) {
throw new Error ( 'Missing EMERGE_WEBHOOK_SECRET' );
}
app . post ( '/webhooks/emerge' , async ( req , res ) => {
try {
const signature = req . headers [ 'x-signature' ] as string | undefined ;
if ( ! signature ) {
return res . status ( 401 ). send ( 'Missing signature' );
}
const expected = crypto
. createHmac ( 'sha256' , WEBHOOK_SECRET )
. update ( req . body )
. digest ( 'hex' );
const signatureBuf = Buffer . from ( signature , 'hex' );
const expectedBuf = Buffer . from ( expected , 'hex' );
const valid =
signatureBuf . length === expectedBuf . length &&
crypto . timingSafeEqual ( signatureBuf , expectedBuf );
if ( ! valid ) {
console . error ( 'Invalid webhook signature' );
return res . status ( 401 ). send ( 'Invalid signature' );
}
const payload = JSON . parse ( req . body . toString ( 'utf8' )) as {
event ?: string ;
uid ?: string ;
sources ?: Array <{ provider ?: string }>;
};
if ( payload . event === 'consent.revoked' && payload . uid ) {
await revokeLocalAccess ( payload . uid , payload . sources ?? []);
}
return res . status ( 200 ). send ( 'OK' );
} catch ( err ) {
console . error ( 'Webhook error' , err );
return res . status ( 500 ). send ( 'Server error' );
}
});
async function revokeLocalAccess ( uid : string , sources : Array <{ provider ?: string }>) {
for ( const source of sources ) {
if ( source . provider ) {
await deleteUserData ( uid , source . provider );
}
}
}
async function deleteUserData ( uid : string , provider : string ) {
console . log ( `Deleting ${ provider } data for ${ uid } ` );
}
app . listen ( 3000 , () => {
console . log ( 'Webhook listener running on http://localhost:3000' );
});
Callbacks Understand redirect behavior after consent
Webhooks Receive consent changes like revocations
Edge cases
If a user opens a completed Link flow again, they are redirected to the Data Wallet instead of your redirect_uri.
If you keep cached data, delete it when you receive consent.revoked to stay privacy-first.