Migrating from Plaid Exchange

Move an existing Plaid Exchange integration to Core Exchange

Why migrate

Plaid Exchange is closed to new integrations; its own documentation directs implementers to Core Exchange, the only specification Plaid continues to develop, covering FDX 4.6 and later. Core Exchange offers self-serve tooling that Plaid Exchange lacks: a Data Partner Dashboard, an in-browser Validator, Permissions Manager, and App Directory.

What's different, at a glance

AreaPlaid ExchangeCore Exchange
Data specPlaid-proprietary schemaFDX-aligned (4.6+)
Endpoints4 endpoints (/oauth2/auth, /oauth2/token, /users/{user_id}, /users/{user_id}/transactions)FDX endpoint set: /customers/current, /accounts, /accounts/{accountId}, /accounts/{accountId}/contact, /accounts/{accountId}/payment-networks, /accounts/{accountId}/statements, /accounts/{accountId}/asset-transfer-networks, /accounts/{accountId}/transactions
Auth modelOAuth 2.0, plus a legacy direct-credential/MFA API Plaid can orchestrateOAuth 2.0 with OIDC strongly recommended; no Plaid-orchestrated MFA API
DiscoveryFixed URLs you give Plaid directly; OIDC discovery and JWKS not supported.well-known/openid-configuration discovery, with jwks_uri for ID token verification
Error modelHTTP status + a small set of error response shapes (BasicErrorResponse, AuthenticationError, InstitutionError)FDX error entity (code, message, debugMessage) with a persistent numeric code, plus a formal token-endpoint error contract (RFC 6749 §5.2)
ToolingManual, via your Solutions EngineerData Partner Dashboard, self-serve Validator, Permissions Manager, App Directory
SupportContact your Solutions Engineer directlySelf-serve Dashboard tickets, routed to a dedicated Data Partner Support Engineering (DPSE) team
Consent visibilityNonePermissions Manager, Data Transparency Messaging (1033)
Returning user experienceEnabled automatically via device/browser fingerprintingEnabled automatically; consumers can additionally opt in with phone verification

Endpoint mapping

Plaid Exchange collapsed identity, account, and transaction data into two endpoints. Core Exchange splits the same data across purpose-specific FDX endpoints:

Plaid ExchangeCore ExchangeNotes
GET /users/{user_id}GET /accounts, GET /accounts/{accountId}, GET /accounts/{accountId}/contactAccount list, account detail, and contact information are now separate calls instead of one combined UserAccountInfoResponse.
GET /users/{user_id}/transactionsGET /accounts/{accountId}/transactionsScoped per account rather than across all of a user's accounts in one call.
(no equivalent; data lived on transfer code models embedded in the account)GET /accounts/{accountId}/payment-networks, GET /accounts/{accountId}/asset-transfer-networksPX represented ACH/EFT/IBAN/card and ACATS transfer identifiers as nested objects (AchTransferCode, EftTransferCode, AcatsTransferCode, and so on) on the account. CX exposes the same kind of identifiers through dedicated endpoints.
(no equivalent)GET /accounts/{accountId}/statements, GET /accounts/{accountId}/statements/{statementId}Account statements are a new capability; PX had a DepositoryAccountStatement/LoanStatement/CreditCardStatement model but no dedicated retrieval endpoint.
id_token.sub, user_id, or GET /customer/current (singular; see Token Flow)sub claim, userinfo_endpoint, or GET /customers/current (plural)The consistency-key fallback endpoint's path changed from singular to plural. Confirm which one your OAuth server is configured to serve before you cut clients over.
POST /users/auth_token, POST /users/{user_id}/sendOtp, POST /users/{user_id}/2fa(no equivalent)See Authentication changes below.

Authentication changes

The overall shape carries over: an OAuth 2.0 authorization code grant, with Plaid redirecting the user to your authorization_endpoint and later exchanging a code at your token_endpoint. A handful of specifics change:

No more Plaid-orchestrated MFA

Plaid Exchange defined a deprecated direct-credential flow (POST /users/auth_token) with Plaid-visible multi-factor escalation: MfaOtpEscalationChallenge, MfaKbaEscalationChallenge, and MfaTotpEscalationChallenge responses, followed by POST /users/{user_id}/sendOtp and POST /users/{user_id}/2fa. Core Exchange has no equivalent endpoints. Plaid requires 2FA for every Core Exchange connection, but the entire authentication flow, including any second factor, happens inside your hosted authorization_endpoint, before redirecting back to Plaid with an authorization code.

What to update: if your PX integration relies on the OTP/KBA/TOTP endpoints rather than pure OAuth, move that challenge logic into your own login flow. There is no code-level migration path for these endpoints; they are removed, not renamed.

OIDC discovery and JWKS

Plaid Exchange did not support OIDC discovery or JWKS; you gave Plaid your authorization_endpoint and token_endpoint directly. Core Exchange strongly recommends OIDC, discovered via .well-known/openid-configuration, with ID tokens verified against keys published at your jwks_uri.

What to update: if you're moving to OIDC as part of this migration (recommended, since OIDC supplies the ID token's sub, the identifier the returning user experience relies on), stand up a discovery document and a JWKS endpoint. See OAuth server setup. Plain OAuth 2.0 without OIDC is still supported; resolve the identifier via /customers/current instead.

New prompt parameters

Core Exchange's authorization redirect includes prompt=login, and its token request includes prompt=consent. Plaid Exchange's flow didn't send either.

What to update: treat an unrecognized prompt value as informational rather than rejecting the request, unless you choose to act on it.

Formal token-endpoint error contract

Plaid Exchange didn't specify a response body for a failed token request. Core Exchange requires HTTP 400 with a JSON body containing error (from a defined code list: invalid_request, invalid_client, invalid_grant, unauthorized_client, unsupported_grant_type, invalid_scope) and optional error_description/error_uri, per RFC 6749 §5.2. Core Exchange defines a convention for an expired access token: return HTTP 401 with error code 602 not authorized. Plaid treats this as an error for that request; it refreshes tokens before the expiration in the expires_in you returned, so don't expire tokens early.

What to update: if your PX token endpoint returns a bare 400/401 with no structured body, add the error field so Plaid can distinguish failure modes.

What doesn't change

No changes needed: the authorization-redirect error vocabulary (invalid_request, unauthorized_client, access_denied, unsupported_response_type, invalid_scope, server_error, temporarily_unavailable) is identical between PX and CX, as is the redirect_uri you send authorization codes back to (https://cdn.plaid.com/link/v2/stable/oauth.html) and the client ID / client secret model.

Data model changes

Plaid Exchange used a Plaid-specific schema (BaseAccount, DepositoryAccount, InvestmentAccount, LoanAccount, CreditCardAccount, BasicIdentity, FullIdentity, and so on), with account type/subtype expressed as lowercase strings (for example depository / checking). Core Exchange uses the FDX-aligned schema documented per version in the API reference. Check the version you're targeting for exact field names, enum values, and discriminators (for example accountCategory), and re-map directly from that schema rather than assuming a 1:1 rename from the PX models.

Plaid Exchange's BasicErrorResponse/AuthenticationError/InstitutionError distinguish failures mainly by HTTP status. Core Exchange's error entity carries a persistent FDX code (for example 705 for "account is closed") alongside message and debugMessage, independent of the HTTP status returned. Build your error handling around the FDX code, not just the status code.

Capabilities not available in Plaid Exchange

None of these require changes to your core data or auth implementation; they are additive once you are live on Core Exchange.

Support and logging

Plaid Exchange support runs through your Solutions Engineer directly, for both routine questions and bug reports. Core Exchange moves this to a self-serve flow: file tickets from the Dashboard under Get Help by selecting Create case and choosing Open finance issues, which route to a dedicated Data Partner Support Engineering (DPSE) team. Solutions Engineering may still re-engage for major expansions or architectural changes.

What to update: update any internal runbooks or on-call documentation that name your Solutions Engineer as the support contact to reference the Dashboard ticketing flow instead.

Core Exchange introduces a logging identifier with no Plaid Exchange equivalent: the X-Request-ID header Plaid sends with requests to your resource server, correlated with the Dashboard's Integration Health view. Keep logging the OAuth state parameter and your user identifier as you did in Plaid Exchange (as oauth_state_id and FI_UNIQUE_ID), and add X-Request-ID alongside them.

Migration path

Before any cohort work begins, sign up for a Data Partner Dashboard account and complete your institution profile: business and compliance details (legal entity name, address, tax ID, Legal Entity Identifier, industry, and licensing or registration such as FDIC, NCUA, or SIPC) and technical contacts. Plaid Exchange never required this; provisioning happened directly with your Plaid contact. See Implementation checklist for the full list.

If your institution already has live PX traffic, Plaid coordinates a phased migration rather than a single cutover, similar to a fresh Core Exchange launch:

  1. Pilot cohort: new connections move to Core Exchange in production for a small cohort while Plaid Exchange keeps serving existing traffic.
  2. Remaining cohorts: expand to the rest of your users, cohort by cohort.
  3. Existing user migration: once integration health is validated, Plaid migrates existing Items from Plaid Exchange over to the Core Exchange OAuth + API connection. This phase runs over approximately 90 days (Plaid Exchange's own migration guidance cites roughly 120 days for the equivalent phase), and in select cases backend token exchange can avoid requiring users to reauthenticate.

Actual timelines depend on institutional health validation and issue resolution; confirm them with your Plaid contact.

After migrating

  • Update your IP allowlist: keep every IP already allowlisted for Plaid Exchange, and add Core Exchange's ranges, 162.120.88.0/22 and 2602:F74B::/40. See IP allowlisting.
  • Run your integration through the Validator before requesting production access on Core Exchange.
  • Decommission the Plaid Exchange OTP/KBA/TOTP endpoints only once Plaid has moved all of your institution's traffic, including any pilot cohorts, over to Core Exchange.
  • Point any internal documentation, client libraries, or generated code at the Core Exchange API reference instead of the Plaid Exchange data definitions.

Additional resources

These aren't specific to migrating from Plaid Exchange, but cover the rest of the Core Exchange onboarding journey: