const FLUZ_GRAPHQL_URL = '<fluz-api-base-url>/api/v1/graphql';
const fluzUserAccessToken = '<fluz-user-access-token>';
const fluzGraphql = async (query, variables) => {
const response = await fetch(FLUZ_GRAPHQL_URL, {
method: 'POST',
headers: {
Authorization: `Bearer ${fluzUserAccessToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ query, variables }),
});
const body = await response.json();
if (!response.ok || body.errors?.length) {
throw new Error(body.errors?.[0]?.message ?? 'Fluz GraphQL request failed');
}
return body.data;
};
const createPlaidLinkToken = async (platformItemId) => {
const data = await fluzGraphql(
`
mutation CreatePlaidLinkToken($input: CreatePlaidLinkTokenInput!) {
createPlaidLinkToken(input: $input) {
linkToken
mode
}
}
`,
{ input: { platformItemId } },
);
return data.createPlaidLinkToken;
};
const completePlaidLink = async (publicToken, platformItemId) => {
const data = await fluzGraphql(
`
mutation CompletePlaidLink($input: CompletePlaidLinkInput!) {
completePlaidLink(input: $input) {
requiresAddress
bankInstitutionAuthId
newlyLinkedBankInstitutionAuthId
bankAccountId
platformItemId
bankAccounts {
bankInstitutionAuthId
bankAccountId
bankName
lastFour
type
subtype
}
}
}
`,
{ input: { publicToken, platformItemId } },
);
return data.completePlaidLink;
};
const getPlaidBankAccounts = async (input) => {
const data = await fluzGraphql(
`
query GetPlaidBankAccounts($input: PlaidBankAccountFilterInput) {
getPlaidBankAccounts(input: $input) {
platformItemId
bankInstitutionAuthId
bankAccountId
bankInstitutionName
lastFour
type
subtype
}
}
`,
{ input },
);
return data.getPlaidBankAccounts;
};
const resolvePlatformItemId = async (completion) => {
if (completion.platformItemId) return completion.platformItemId;
const bankInstitutionAuthId =
completion.bankInstitutionAuthId ?? completion.newlyLinkedBankInstitutionAuthId;
const accounts = await getPlaidBankAccounts({ bankInstitutionAuthId });
return accounts[0]?.platformItemId;
};
const startPlaidLink = async (platformItemId) => {
const { linkToken } = await createPlaidLinkToken(platformItemId);
const handler = window.Plaid.create({
token: linkToken,
onSuccess: async (publicToken, metadata) => {
const result = await completePlaidLink(publicToken, platformItemId);
const persistedPlatformItemId = await resolvePlatformItemId(result);
await saveConnectionForRelinkLater({
platformItemId: persistedPlatformItemId,
bankInstitutionAuthId:
result.bankInstitutionAuthId ?? result.newlyLinkedBankInstitutionAuthId,
bankAccounts: result.bankAccounts,
plaidLinkSessionId: metadata.link_session_id,
});
},
onExit: (error, metadata) => {
console.log('Plaid Link exited', { error, metadata });
},
});
handler.open();
};