Plaid logo
Core Exchange
ALL DOCS

Reference

  • API reference
  • Changelog
  • Migration guide
  • Migrating from Plaid Exchange
Core Exchange
Close search modal
Ask Bill!
Ask Bill!
Hi! I'm Bill! You can ask me all about Core Exchange. Try asking questions like:
    Note: Bill isn't perfect. He's just a robot platypus that reads our docs for fun. You should treat his answers with the same healthy skepticism you might treat any other answer on the internet. This chat may be logged for quality and training purposes. Please don't send Bill any PII -- he's scared of intimacy. All chats with Bill are subject to Plaid's Privacy Policy.
    Plaid.comGet Started
    Open nav

    Migration guide

    Upgrade an existing Core Exchange integration to get the latest functionality

    This guide covers every breaking change and major new capability added to Core Exchange from v4.6 through v6.4, in version order. Each item is tagged with the version that introduced it. For the full field-by-field history, see the Changelog.

    Why migrate

    v6.x is the current Core Exchange specification, aligned with FDX 6.x, and each version since v4.6 has added capabilities that aren't available on earlier ones — see New capabilities by version below.

    New capabilities by version

    • v5.0 — An AUTHORIZED_USER account holder relationship type.
    • v5.1 — Digital asset holdings and securities (DIGITALASSET), and the US_RTP real-time payment network.
    • v5.2 — GET /accounts/{accountId}/statements and GET /accounts/{accountId}/statements/{statementId}, for retrieving account statements. Business customer support (BusinessCustomer), so /customers/current can represent a business rather than only an individual. Canadian retirement and tax-advantaged investment account types.
    • v5.3 — A dedicated CommercialAccountType (see Commercial account types moved to their own schema).
    • v6.0 — GET /accounts/{accountId}/asset-transfer-networks, which returns the identifiers needed to submit an inter-institution investment account transfer (ACATS, DTC, or ATON). See New endpoint: asset transfer networks.
    • v6.2 — Digital wallet accounts (DIGITAL_WALLET category), the ZWG currency code, and a PREPAID investment account type.
    • v6.3 — pageKey-based pagination on list endpoints, new savings account types, expanded contact fields (authorized signers, phone number type/network/primary), student loan details (currentSchool, loanProviderName), masked card numbers on transactions, and date-range filtering on statements and transactions.
    • v6.4 — Interest-rate reporting on deposit, investment, loan, and line-of-credit accounts; overdraft fields on deposit accounts; scheduled payments and bills on line-of-credit accounts; loan APR; and a productId on account descriptors.

    Breaking changes

    Some date-time fields converted to date only (v5.0 and later)

    Certain fields that were inappropriately treated as date-time but actually represent dates were changed to date fields. Impacted fields are: LoanAccount.originatingDate, nextPaymentDate, lastPaymentDate, and maturityDate; LineOfCreditAccount.nextPaymentDate, lastPaymentDate, and lastStmtDate; and Holding.currentUnitPriceDate and TaxLot.originalPurchaseDate

    Before v5.0
    {
      "maturityDate": "2050-07-15T00:00:00.000Z"
    }
    v5.0 or later
    {
      "maturityDate": "2050-07-15"
    }

    What to update: if you send a full timestamp for any of these fields, truncate it to the date component.

    state renamed to region on Address (v5.0 and later)

    The state property on the Address schema was renamed to region.

    What to update: any response-mapping code that sets state needs to set region instead.

    Country and currency codes updated (v5.3 and later)

    Country codes moved to the ISO 3166-1 alpha-2 standard, and currency codes were updated to the ISO 4217 list current as of January 1, 2023. AN and CS are no longer valid country codes; HRK is no longer a valid currency code.

    What to update: For HRK (Croatian kuna), return EUR instead, as Croatia has adopted the euro. For AN (Netherlands Antilles) and CS (Serbia and Montenegro) map each account to the appropriate code: CW (Curaçao), SX (Sint Maarten), or BQ (Bonaire, Sint Eustatius and Saba) for former AN accounts, and RS (Serbia) or ME (Montenegro) for former CS accounts.

    Commercial account types moved to their own schema (v5.3 and later)

    COMMERCIALDEPOSIT, COMMERCIALLOAN, COMMERCIALLINEOFCREDIT, and COMMERCIALINVESTMENT are no longer valid values of DepositAccountType, LoanAccountType, LocAccountType, and InvestmentAccountType. They're now reported under a dedicated CommercialAccountType, using a new commercialAccount wrapper key in the /accounts list response:

    Before v5.3
    {
      "depositAccount": {
        "accountType": "COMMERCIALDEPOSIT"
      }
    }
    v5.3 or later
    {
      "commercialAccount": {
        "accountType": "COMMERCIALDEPOSIT"
      }
    }

    What to update: if you report commercial accounts, switch them from their prior account-type wrapper to commercialAccount.

    Account and transaction responses are no longer wrapped (v6.0 and later)

    GET /accounts, GET /accounts/{accountId}, and GET /accounts/{accountId}/transactions no longer wrap the account or transaction object in a named property that identified its type (for example depositAccount or depositTransaction). Each object is returned directly and must carry a required discriminator field, accountCategory, identifying its type:

    Before v6.0
    {
      "depositAccount": {
        "accountId": "12345",
        "accountNumberDisplay": "...5678"
      }
    }
    v6.0 or later
    {
      "accountCategory": "DEPOSIT_ACCOUNT",
      "accountId": "12345",
      "accountNumberDisplay": "...5678"
    }

    The accepted values differ by endpoint:

    EndpointAccepted accountCategory values
    GET /accountsANNUITY_ACCOUNT, COMMERCIAL_ACCOUNT, DEPOSIT_ACCOUNT, DIGITAL_WALLET (v6.2 and later), INSURANCE_ACCOUNT, INVESTMENT_ACCOUNT, LOAN_ACCOUNT, LOC_ACCOUNT
    GET /accounts/{accountId}DEPOSIT_ACCOUNT, INVESTMENT_ACCOUNT, LOAN_ACCOUNT, LOC_ACCOUNT
    GET /accounts/{accountId}/transactionsDEPOSIT_ACCOUNT, INVESTMENT_ACCOUNT, LOAN_ACCOUNT, LOC_ACCOUNT

    The accountCategory field itself is new in v6.0; the categories it names correspond to the wrapper keys it replaces.

    What to update: any response-mapping code keyed on the wrapper property name (depositAccount, investmentAccount, etc.) needs to key on accountCategory instead, and your mapping must explicitly set that field on every account and transaction you return.

    Investment holdings use a securityIds array (v6.0 and later)

    An investment holding previously identified its security with a single securityId/securityIdType pair. That pair is replaced by a securityIds array of { id, idType } objects, allowing a holding to report multiple identifier types for the same security.

    Before v6.0
    {
      "securityId": "037833100",
      "securityIdType": "CUSIP"
    }
    v6.0 or later
    {
      "securityIds": [{ "id": "037833100", "idType": "CUSIP" }]
    }

    What to update: map your existing single identifier into a one-element securityIds array at minimum; add additional entries if you have more than one identifier type available for a security.

    Telephone number country format has stricter validation (v6.3 and later)

    telephones[].country now must match the pattern of an optional leading + followed by 1-3 digits, no leading zero. (Previously any string up to 3 characters was accepted.) maxLength also increased from 3 to 4 to accommodate the optional +.

    What to update: confirm every telephones[].country value you send is valid.

    Non-breaking changes

    Statement status is no longer a fixed set of values (v6.2 and later)

    The statement status enum, which had constrained the field to AVAILABLE, PROCESSING, and FAILED, was removed entirely. status is now an unconstrained string.

    What to update: no action is required.

    Line of credit schema names changed (v6.0 and later)

    LocAccount, LocAccountDescriptor, LocAccountType, LocTransaction, and LocTransactionType are renamed to LineOfCreditAccount, LineOfCreditAccountDescriptor, LineOfCreditAccountType, LineOfCreditTransaction, and LineOfCreditTransactionType respectively. The LOC_ACCOUNT discriminator value and every field name and JSON response shape are unchanged.

    What to update: regenerate client code or server stubs if you generate them directly from Plaid's OpenAPI file.

    New endpoint: asset transfer networks (v6.0 and later)

    GET /accounts/{accountId}/asset-transfer-networks returns the identifiers needed to submit inter-institution investment account transfers via ACATS, DTC, or ATON.

    This endpoint backs Investments Move. Without it, the requesting party falls back to asking the end user to manually enter account and holdings details, which increases the rate of rejected (NIGO) transfer requests reaching your transfer desk. Implementing the endpoint reduces that rejection rate by supplying verified data up front.

    Telephone number purpose schema renamed, CELL deprecated (v6.3 and later)

    The type field on a telephone number now references TelephoneNumberPurpose instead of TelephoneNumberType, and adds BOTH and PERSONAL values. Every previously valid type value, including CELL, is still valid. CELL is marked deprecated in favor of reporting a separate network field as CELLULAR, but existing implementations that keep sending CELL are not broken by this change.

    What to update: no action is required. Optionally, move cell numbers to type: PERSONAL (or HOME/BUSINESS, as applicable) plus network: CELLULAR.

    After migrating

    • Re-run the Validator against your updated build before requesting production access for the new version.
    • Update any internal documentation or generated client code that references the old wrapped response shape, Loc* schema names, or state on Address.