Permissions Manager API

Read connected applications, consent activity, and revoke access

Overview

The Permissions Manager API reports which Plaid-powered applications one of your customers has connected, which accounts and data types each application can read, and when each application last read them. It also lets you revoke an application's access.

It is the API behind a consumer-facing consent portal on your domain: the customer sees their connections and disconnects the ones they no longer want, and Plaid enforces that revocation across the ecosystem. Single-institution accounts can read the same data with no code in the Data Partner Dashboard, whose Permissions Manager tabs call these same endpoints; this page covers the API, which is available to every integration model, including platforms.

For conceptual background on authorization records and the webhooks that accompany these endpoints, see Consent management.

Authentication

Find your client_id and secret on the Keys page of the Data Partner Dashboard. Include both as the PLAID-CLIENT-ID and PLAID-SECRET headers, or as client_id and secret in the request body. All requests must be made over HTTPS.

Customer identifiers and access tokens

Permissions Manager identifies a customer by an access_token, not by a customer identifier, so every integration starts with /item/import.

Use the same persistent, unique identifier you use as the sub claim in your OIDC ID token — see Unique user identifier (consistency key). Reusing an identifier across two customers merges their connections; changing it for an existing customer strands the connections recorded under the old one.

Because /item/import is idempotent, you can call it lazily the first time a customer opens your portal, batch it ahead of time, or call it again whenever you need the token.

Exchange a customer identifier for an access token

POST /item/import

Import Item

/item/import creates an Item for one of your customers and returns an access_token, which the other Permissions Manager endpoints take in place of a customer identifier. You supply your own identifier for the customer as user_auth.user_id.

The endpoint is idempotent and the access_token it returns is long-lived: repeated calls for the same user_auth.user_id return the same token.

Upon creating an Item via /item/import, Plaid will automatically begin an extraction of that Item through the data provider API endpoints you have already integrated.

/item/import

Request fields

client_id
stringstring

Your Plaid API client_id. The client_id is required and may be provided either in the PLAID-CLIENT-ID header or as part of a request body.

secret
stringstring

Your Plaid API secret. The secret is required and may be provided either in the PLAID-SECRET header or as part of a request body.

institution_id
stringstring

The Plaid Institution ID associated with the Item. Most callers omit this field; Plaid resolves your institution automatically. If your organization has multiple institutions, contact Plaid to determine whether you should send it.

user_auth
requiredobjectrequired, object

Object of user ID and auth token pair, permitting Plaid to aggregate a user's accounts

user_id
requiredstringrequired, string

Your persistent, unique identifier for the customer.

curl -X POST 'https://production.plaid.com/item/import' \
  -H 'Content-Type: application/json' \
  -d '{
    "client_id": "<client_id>",
    "secret": "<secret>",
    "user_auth": {
      "user_id": "<user_id>"
    }
  }'
/item/import

Response fields

access_token
stringstring

The access token associated with the Item for which data is being requested.

request_id
stringstring

A unique identifier for the request, which can be used for troubleshooting. This identifier, like all Plaid identifiers, is case sensitive.

Response Object
{
  "access_token": "access-sandbox-99ace160-3cf7-4e51-a083-403633425815",
  "request_id": "ewIBAn6RZirsk4W"
}

Endpoints

EndpointFunctionality
/item/importExchange your customer identifier for an access token
/item/application/listList connected and disconnected applications, with their scopes
/item/activity/listRead consent activity history and per-scope last-access times
/item/application/unlinkRevoke an application's access to a customer's data
/sandbox/item/application/seedSandbox only: connect a demo application to a customer

List a customer's connected applications

POST /item/application/list

Call this each time a customer opens your portal rather than serving a cached copy, so that revocations made elsewhere in the ecosystem are reflected immediately.

The response separates applications, which the customer has authorized, from disconnected_applications, which they authorized and later revoked. Render disconnected applications as history: they carry no scopes or created_at, because there is no longer any access to describe.

Parse created_at permissively. Depending on when your integration was set up, it arrives either as an ISO 8601 datetime (2020-01-01T00:00:00Z) or as a date alone (2020-01-01).

List a user's connected applications

List a user's connected applications

/item/application/list

Request fields

client_id
stringstring

Your Plaid API client_id. The client_id is required and may be provided either in the PLAID-CLIENT-ID header or as part of a request body.

secret
stringstring

Your Plaid API secret. The secret is required and may be provided either in the PLAID-SECRET header or as part of a request body.

access_token
stringstring

The access token associated with the Item for which data is being requested.

curl -X POST 'https://production.plaid.com/item/application/list' \
  -H 'Content-Type: application/json' \
  -d '{
    "client_id": "<client_id>",
    "secret": "<secret>",
    "access_token": "<access_token>"
  }'
/item/application/list

Response fields

request_id
stringstring

A unique identifier for the request, which can be used for troubleshooting. This identifier, like all Plaid identifiers, is case sensitive.

applications
[object][object]

A list of connected applications.

application_id
stringstring

This field will map to the application ID that is returned from /item/application/list, or provided to the institution in an oauth redirect.

name
stringstring

The name of the application

display_name
nullablestringnullable, string

A human-readable name of the application for display purposes

logo_url
nullablestringnullable, string

A URL that links to the application logo image.

application_url
nullablestringnullable, string

The URL for the application's website

reason_for_access
nullablestringnullable, string

A string provided by the connected app stating why they use their respective enabled products.

created_at
stringstring

The date and time this application was linked, in ISO 8601 format in UTC (e.g. "2020-01-01T00:00:00Z"). Note that older, legacy integrations instead receive this value as a date only, in YYYY-MM-DD format (e.g. "2020-01-01").

Format: date-time
scopes
nullableobjectnullable, object

The scopes object

product_access
objectobject

The product access being requested. Used to allow or disallow product access across all accounts. If unset, defaults to all products allowed.

statements
nullablebooleannullable, boolean

Allow access to statements. Only used by certain partners. If relevant to the partner and unset, defaults to true.

Default: true
identity
nullablebooleannullable, boolean

Allow access to the Identity product (name, email, phone, address). Only used by certain partners. If relevant to the partner and unset, defaults to true.

Default: true
auth
nullablebooleannullable, boolean

Allow access to account number details. Only used by certain partners. If relevant to the partner and unset, defaults to true.

Default: true
transactions
nullablebooleannullable, boolean

Allow access to transaction details. Only used by certain partners. If relevant to the partner and unset, defaults to true.

Default: true
accounts_details_transactions
nullablebooleannullable, boolean

Allow access to accounts_details_transactions. Only used by certain partners. If relevant to the partner and unset, defaults to true.

Default: true
accounts_routing_number
nullablebooleannullable, boolean

Allow access to accounts_routing_number. Only used by certain partners. If relevant to the partner and unset, defaults to true.

Default: true
accounts_statements
nullablebooleannullable, boolean

Allow access to accounts_statements. Only used by certain partners. If relevant to the partner and unset, defaults to true.

Default: true
accounts_tax_statements
nullablebooleannullable, boolean

Allow access to accounts_tax_statements. Only used by certain partners. If relevant to the partner and unset, defaults to true.

Default: true
customers_profiles
nullablebooleannullable, boolean

Allow access to customers_profiles. Only used by certain partners. If relevant to the partner and unset, defaults to true.

Default: true
accounts
[object][object]
unique_id
stringstring

The unique account identifier for this account. This value must match that returned by the data access API for this account.

authorized
nullablebooleannullable, boolean

Allow the application to see this account (and associated details, including balance) in the list of accounts. If unset, defaults to true.

Default: true
account_product_access
nullableobjectnullable, object

Allow the application to access specific products on this account

account_data
nullablebooleannullable, boolean

Allow the application to access account data. Only used by certain partners. If relevant to the partner and unset, defaults to true.

Default: true
statements
nullablebooleannullable, boolean

Allow the application to access bank statements. Only used by certain partners. If relevant to the partner and unset, defaults to true.

Default: true
tax_documents
nullablebooleannullable, boolean

Allow the application to access tax documents. Only used by certain partners. If relevant to the partner and unset, defaults to true.

Default: true
new_accounts
nullablebooleannullable, boolean

Allow access to newly opened accounts as they are opened. If unset, defaults to true.

Default: true
disconnected_applications
[object][object]

A list of applications that the user previously connected and has since disconnected. Disconnected applications carry no scopes or created_at, since the user has revoked their access.

application_id
stringstring

This field will map to the application ID that is returned from /item/application/list, or provided to the institution in an oauth redirect.

name
stringstring

The name of the application

display_name
nullablestringnullable, string

A human-readable name of the application for display purposes

logo_url
nullablestringnullable, string

A URL that links to the application logo image.

application_url
nullablestringnullable, string

The URL for the application's website

reason_for_access
nullablestringnullable, string

A string provided by the connected app stating why they use their respective enabled products.

Response Object
{
  "applications": [
    {
      "application_id": "c048eab9-a70a-42fe-94e9-35980d0a965c",
      "name": "Big FinTech App",
      "display_name": "Big FinTech",
      "logo_url": "https://plaid.com/images/1",
      "application_url": "https://bigfintechapp.com",
      "reason_for_access": "to display your balances",
      "created_at": "2019-07-16T19:20:00Z",
      "scopes": {
        "product_access": {
          "account_balance_info": true,
          "account_routing_number": true,
          "transactions": false
        },
        "accounts": [
          {
            "unique_id": "4a94ed625e7c",
            "authorized": true
          },
          {
            "unique_id": "6068084d3aab",
            "authorized": false
          }
        ],
        "new_accounts": true
      }
    }
  ],
  "disconnected_applications": [
    {
      "application_id": "d348deb9-a70a-67fe-52b9-35980d0a965c",
      "name": "Another FinTech App",
      "display_name": "Another FinTech",
      "logo_url": "https://plaid.com/images/2",
      "application_url": "https://anotherfintechapp.com",
      "reason_for_access": "to display your balances"
    }
  ],
  "request_id": "m8MDnv9okwxFNBV"
}

Reading the scopes object

scopes.product_access maps a data type to whether the customer authorized it. The keys that can appear are:

KeyIncludes
account_balance_infoAccount name, type, description, balances, and masked account number
contact_infoAccount owner name, email, phone, and address
account_routing_numberAccount and routing numbers
transactionsTransaction amounts, dates, descriptions, and categories, and derived insights
credit_loan_infoBalances, payment dates and amounts due, credit limits, rates, and loan terms
investmentsSecurities details, quantities, prices, and investment transactions
bank_statementsPDF statements

Only the data types an application requested appear, so treat a missing key as "not authorized" rather than as an error. Applications built on Plaid products outside this set can introduce further keys, so parse product_access as a map rather than a fixed struct.

If you integrated before June 2024, your product_access keys may use different field names than the ones in the table above. Contact your Plaid solutions engineering team if you'd like to migrate to the new field names.

scopes.accounts lists the customer's accounts by unique_id — the same account identifier your FDX API returns — each with whether the application may read it. new_accounts reports whether accounts the customer opens later are included automatically. An empty accounts array on a long-standing connection means the customer authorized every available account; those connections predate per-account selection.

Where you scope data types per account rather than per connection, each account also carries account_product_access, keyed by the per-account scopes configured for your integration.

Read consent activity and last access times

POST /item/activity/list

/item/activity/list is the audit view of your portal: what happened to a customer's connections, and when each application last read their data. Results are paginated: pass count to size a page and the cursor from the previous response to fetch the next one. An omitted cursor in the response means you have reached the end.

List a historical log of user consent events

List a historical log of user consent events

/item/activity/list

Request fields

client_id
stringstring

Your Plaid API client_id. The client_id is required and may be provided either in the PLAID-CLIENT-ID header or as part of a request body.

secret
stringstring

Your Plaid API secret. The secret is required and may be provided either in the PLAID-SECRET header or as part of a request body.

access_token
stringstring

The access token associated with the Item for which data is being requested.

cursor
stringstring

Cursor used for pagination.

count
integerinteger
curl -X POST 'https://production.plaid.com/item/activity/list' \
  -H 'Content-Type: application/json' \
  -d '{
    "client_id": "<client_id>",
    "secret": "<secret>",
    "access_token": "<access_token>"
  }'

Each entry in activities records one event. activity is the event type, initiated_date is when it happened, state is its outcome, initiator identifies who caused it, and target_application_id names the application it acted on:

activityRecorded when
ITEM_CREATEThe customer connected an application
ITEM_UNLINKAn application's access ended, including through /item/application/unlink
PORTAL_UNLINKThe customer disconnected an application in Plaid Portal
PORTAL_ITEM_DELETEThe customer deleted their data in Plaid Portal
ITEM_REMOVEThe connected application removed the connection on its own side
SCOPES_UPDATEThe scopes on a connection were updated

last_data_access_times holds one object per application, keyed by application_id, with a timestamp for every product_access scope except bank_statements. A null timestamp means the application has never read that data type. This is the field to show a customer who wants to know whether an app they authorized months ago is still reading their accounts.

If you integrated before June 2024, your last_data_access_times object may use different field names than the ones above, and may also include payroll_info and transaction_risk_info, which are deprecated. Contact your Plaid solutions engineering team if you'd like to migrate to the new field names.

Revoke an application's access

POST /item/application/unlink

Call this endpoint as soon as a customer disconnects an application in your portal, one call per application, and never in a batch — Plaid revokes the application's access on receipt, and the delay before that call is time the application can still read data.

If you offer users the ability to revoke access, you must keep the ecosystem in sync:

  1. User revokes access on your domain: The customer visits your consent portal and disconnects an application
  2. Call /item/application/unlink: Your system calls Plaid's revocation endpoint
  3. Plaid notifies the application: Plaid sends the application a USER_PERMISSION_REVOKED webhook
  4. Plaid severs the connection: Plaid blocks the application from accessing data
  5. Application stops requesting data: The application knows the customer revoked access and stops making requests

Without step 2, the application keeps its access and your portal shows a disconnection that never took effect.

A customer who wants the application again has to go through your OAuth flow from the start; there is no way to restore a revoked connection.

Unlink a user's connected application

Unlink a user's connected application. On an unlink request, Plaid will immediately revoke the Application's access to the User's data. The User will have to redo the OAuth authentication process in order to restore functionality.

This endpoint only removes ongoing data access permissions, therefore the User will need to reach out to the Application itself in order to disable and delete their account and delete any data that the Application already received (if the Application does not do so by default).

This endpoint should be called in real time as the User is unlinking an Application, and should not be batched in order to ensure that the change is reflected as soon as possible.

/item/application/unlink

Request fields

client_id
stringstring

Your Plaid API client_id. The client_id is required and may be provided either in the PLAID-CLIENT-ID header or as part of a request body.

secret
stringstring

Your Plaid API secret. The secret is required and may be provided either in the PLAID-SECRET header or as part of a request body.

access_token
requiredstringrequired, string

The access token associated with the Item for which data is being requested.

application_id
requiredstringrequired, string

This field will map to the application ID that is returned from /item/application/list, or provided to the institution in an oauth redirect.

curl -X POST 'https://production.plaid.com/item/application/unlink' \
  -H 'Content-Type: application/json' \
  -d '{
    "client_id": "<client_id>",
    "secret": "<secret>",
    "access_token": "<access_token>",
    "application_id": "<application_id>"
  }'
/item/application/unlink

Response fields

request_id
stringstring

A unique identifier for the request, which can be used for troubleshooting. This identifier, like all Plaid identifiers, is case sensitive.

Response Object
{
  "request_id": "m8MDnv9okwxFNBV"
}

Webhooks

Plaid can optionally send webhooks to you when authorization events occur. They are independent of which API you read with. Single-institution accounts can configure them in the Data Partner Dashboard via the Webhooks page. Platform accounts should reach out to your Plaid contact to have these enabled.

Webhook configuration interface in the Data Partner Dashboard
Configure webhooks for real-time connection and disconnection alerts

Plaid sends two webhooks: CONSENT_GRANTED and CONSENT_REVOKED. For the payload shape and full examples, see Webhooks on the Consent API reference.

CONSENT_GRANTED

Notifies you every time a customer connects a new application via Plaid. While your system will already know about new OAuth authorizations, this webhook also alerts you to connections created via the returning user experience, where the customer never goes through your OAuth flow and this webhook is your only real-time signal that a new connection was created.

When it fires: After a customer successfully authorizes a new application.

Payload includes: The customer (user_identifier) and application details (application_id, application_name).

Partners that were already receiving this webhook before August 2026 still receive it under its earlier names, category AUTHORIZATION and type AUTHORIZATION_GRANTED.

What to do: Record the new connection. The webhook identifies the customer and the application, but not the accounts or data types they authorized, so treat it as a signal to call /item/application/list for the full set of scopes. If you offer a consent portal, display this new connection so customers can view and manage it.

CONSENT_REVOKED

Notifies you when a customer revokes an application's access, either through the application itself or via my.plaid.com (Plaid Portal). If you offer a consent portal, you need this webhook to catch the revocations that happen elsewhere; otherwise your portal will drift out of sync when customers disconnect through my.plaid.com or the application itself instead of through you.

When it fires: After a customer or application revokes authorization.

Payload includes: The customer (user_identifier), application details, and who initiated the revocation (initiator: DATA_ACCESS_PLATFORM, INDIVIDUAL, or DATA_RECIPIENT).

What to do: Mark the connection revoked in your own records and update your portal. Revocations that happen in Plaid Portal or in the application itself also land in /item/activity/list as PORTAL_UNLINK and ITEM_REMOVE entries.

Best practices

  • Call /item/application/unlink as soon as a customer disconnects an application, to keep the ecosystem in sync during revocations
  • Implement the CONSENT_REVOKED webhook if you offer a consent portal
  • Set refresh token expiration to 13+ months (allows buffer for reauthorization)
  • Direct users to my.plaid.com for self-service connection management

Testing in Sandbox

Point the same calls at sandbox.plaid.com with your Sandbox secret. /item/import returns a working Sandbox access token, and /item/application/list and /item/activity/list return fixture data for demo applications, so you can build and test your portal's rendering before you have live connections.

That fixture data is static: unlinking a demo application does not change what /item/application/list returns. To exercise the state changes instead, use dynamic Sandbox, which is enabled for most clients: connect a demo app, see it appear in /item/application/list, unlink it, and see it move to disconnected_applications. /sandbox/item/application/seed connects a demo application to a customer, standing in for a customer completing your OAuth flow. If it returns 403 SANDBOX_SEEDING_NOT_ENABLED, dynamic Sandbox is off for your client — ask your Plaid solutions engineering team to enable it. /item/activity/list always serves its fixture in Sandbox, dynamic Sandbox or not, so you can build your portal's activity view against it, but you won't see real activity until Production.

POST /sandbox/item/application/seed

Seed a connected application for a Permissions Manager sandbox item

/sandbox/item/application/seed creates a test connected application on an existing Permissions Manager Item's login. The seeded application will appear in subsequent calls to /item/application/list.

The access_token must belong to a Permissions Manager Item created via /item/import in Sandbox. The application_id identifies the application to seed as a connected app. To disconnect a seeded application, use /item/application/unlink.

/sandbox/item/application/seed

Request fields

client_id
stringstring

Your Plaid API client_id. The client_id is required and may be provided either in the PLAID-CLIENT-ID header or as part of a request body.

secret
stringstring

Your Plaid API secret. The secret is required and may be provided either in the PLAID-SECRET header or as part of a request body.

access_token
requiredstringrequired, string

The access token associated with the Item for which data is being requested.

application_id
requiredstringrequired, string

This field will map to the application ID that is returned from /item/application/list, or provided to the institution in an oauth redirect.

curl -X POST 'https://sandbox.plaid.com/sandbox/item/application/seed' \
  -H 'Content-Type: application/json' \
  -d '{
    "client_id": "<client_id>",
    "secret": "<sandbox_secret>",
    "access_token": "<access_token>",
    "application_id": "c048eab9-a70a-42fe-94e9-35980d0a965c"
  }'
/sandbox/item/application/seed

Response fields

item_id
stringstring

The item_id of the newly seeded item representing the application connection.

request_id
stringstring

A unique identifier for the request, which can be used for troubleshooting. This identifier, like all Plaid identifiers, is case sensitive.

Response Object
{
  "item_id": "9xGbdRaG3gianaxoELGpILQ7drV3RnclMGdKJ",
  "request_id": "m8MDnv9okwxFNBV"
}

Plaid provides three demo applications to connect:

Demo applicationapplication_id
Budget Worksc048eab9-a70a-42fe-94e9-35980d0a965c
Incremental Investing36b78a27-ebbb-417b-a7b7-351734d2f8bd
My Peer Payer3f952a96-b6f9-4f09-a1f7-1a474cb128f6

Errors

These endpoints return Plaid's standard error object (error_type, error_code, error_message, display_message, request_id). Log request_id when you encounter an error to speed up troubleshooting with Plaid.

Statuserror_codeReturned when
400MISSING_FIELDSA required field is absent from the request body
400INVALID_USER_AUTHuser_auth.user_id is missing or is not a non-empty string
400ITEM_NOT_CREATED_BY_ITEM_IMPORTThe access_token belongs to an Item created some other way than /item/import
400ITEM_IMPORT_INACTIVE_ACCESS_TOKENThe access_token is no longer active
400FI_PARTNER_INSTITUTION_NOT_SET_UPYour institution is not configured for Permissions Manager — contact your Plaid solutions engineering team
404CONNECTED_APPLICATION_NOT_FOUNDThe application_id and access_token pair has no active connection
404NO_CONNECTED_APPLICATIONSThe customer has no connections, for the older integrations that receive a 404 for this rather than a 200

A customer with no connections is a normal state, not a failure: /item/application/list returns 200 with an empty applications array. If you integrated before February 2022, you may receive 404 NO_CONNECTED_APPLICATIONS instead; render either as an empty portal.

Unlinking an application whose access has already ended returns 204 with APPLICATION_ALREADY_UNLINKED. Treat it as success — the revocation you asked for is already in effect — which makes retries safe.