fastify-xplaid
link.exchangePublicToken
Exchange a Plaid public token for a permanent access token after the user completes Plaid Link.
link.exchangePublicToken
Exchange the temporary one-time public_token received from Plaid Link's onSuccess callback for a permanent accessToken and itemId. Always call this server-side — never expose the access token to the browser.
Signature
fastify.xplaid.link.exchangePublicToken(
publicToken: string
): Promise<{ accessToken: string; itemId: string; requestId: string }>
Params
| Name | Type | Required | Description |
|---|---|---|---|
publicToken | string | Yes | The public_token from Plaid Link's onSuccess callback. Starts with public-. |
Returns
| Field | Type | Description |
|---|---|---|
accessToken | string | Permanent access token for this Item. Store encrypted in your database. |
itemId | string | Plaid Item ID — stable identifier for the linked bank connection. |
requestId | string | Plaid request ID for support and logging. |
Throws
[xPlaid] publicToken is required and must be a non-empty string— whenpublicTokenis missing or empty.- Plaid API errors wrapped via
wrapPlaidError— shape:{ message, statusCode, plaidError }.
Examples
Basic — exchange and store
fastify.post("/plaid/exchange-token", async (request, reply) => {
const { publicToken, institutionId } = request.body;
const { accessToken, itemId } = await fastify.xplaid.link.exchangePublicToken(publicToken);
// Never return the accessToken to the client
await db.plaidItems.create({
data: {
userId: request.user.id,
accessToken: encrypt(accessToken),
itemId,
institutionId,
},
});
return reply.code(201).send({ itemId });
});
Realistic — exchange, fetch accounts, and persist
fastify.post("/plaid/connect", async (request, reply) => {
const { publicToken, metadata } = request.body;
let accessToken, itemId;
try {
({ accessToken, itemId } = await fastify.xplaid.link.exchangePublicToken(publicToken));
} catch (error) {
if (error.plaidError) {
request.log.error({ code: error.plaidError.error_code }, "Token exchange failed");
return reply.status(error.statusCode ?? 500).send({ error: error.message });
}
throw error;
}
const { accounts } = await fastify.xplaid.accounts.get(accessToken);
await db.plaidItems.create({
data: {
userId: request.user.id,
itemId,
accessToken: encrypt(accessToken),
institutionName: metadata.institution.name,
accounts: accounts.map((a) => ({
id: a.account_id,
name: a.name,
type: a.type,
subtype: a.subtype,
mask: a.mask,
})),
},
});
return reply.code(201).send({
itemId,
institutionName: metadata.institution.name,
accountCount: accounts.length,
});
});
See also
- link.createToken — Create the Link token that precedes this call.
- link.getToken — Inspect metadata for an existing Link token.
- accounts.get — Fetch accounts immediately after exchanging a public token.
- transactions.sync — Start syncing transactions with the new access token.
- sandbox.createPublicToken — Skip the Link UI in tests by creating a public token directly.
AI Context
package: "@xenterprises/fastify-xplaid"
method: fastify.xplaid.link.exchangePublicToken(publicToken)
use-when: Exchange the temporary one-time public_token from Plaid Link's onSuccess callback for a permanent accessToken — call server-side only, never expose the accessToken to the browser
params: publicToken (string, starts with "public-")
returns: { accessToken, itemId, requestId }
