Item Lifecycle
Overview
A Plaid item represents a user’s connection to a financial institution. It holds the Plaid access_token and item_id that are used for all subsequent data retrieval (transactions, accounts, balances, liabilities). A user can have multiple items, but typically only one is active at a time.
Items are created when a user links their bank account via Plaid Link. They transition through a defined set of statuses and are removed when the user disconnects their bank or cancels their account.
During reactivation, the item will have a TTL set when first created. The TTL is later if the user successfully completes reactivation. This will allow the item to be cleaned up if the user never completes the reactivation process.
See Plaid: Items for the full DynamoDB schema.
Item Statuses
| Status | Error Code | Description |
|---|---|---|
|
(empty) |
Item is connected and healthy. Transactions and accounts are being mined successfully. |
|
|
The user’s bank credentials have expired or changed. The user must re-authenticate via Plaid Link update mode. |
|
|
No accessible accounts were found on the item. |
|
(any) |
Item has been disconnected. The access token has been revoked at Plaid. No further mining occurs. |
Add Item Flow
Adding a new item is the primary onboarding step. The mobile app calls Plaid Link, receives a public_token, and submits it to the API. Version 2 (POST /{user_id}/transactions/items-v2) is the current preferred endpoint.
POST /{user_id}/transactions/items-v2
{ account_id, public_token, institution_id,
is_reactivating, skip_activation }
│
▼
Exchange public_token → access_token + item_id (Plaid)
│
▼
Set webhook URL on item (Plaid)
│ Kicks off INITIAL_UPDATE webhook → mining pipeline
▼
If is_reactivating flag is set to true, set a TTL on the item.
│
▼
Save item record in DynamoDB
status: ACTIVE
main_account_id: provided account_id
│
▼
If existing items have a different main_account_id:
Update all existing items to use the new main_account_id
(maintains consistency across multiple items)
│
▼
Encrypt account + routing numbers (Payments Service)
│
▼
skip_activation = false?
└─► Activate user in User Service
(sets user status → ACTIVE, activates subscription + membership)
│
▼
Emit item-created event to EventBridge
│
▼
Return 201 Created
AddItem v1 (POST /{user_id}/transactions/items) is deprecated. It has the same core flow but lacks the multi-item main account consistency logic introduced in v2.
|
Update Item Flow
Updating an item changes the main_account_id — the account used for float disbursements and subscription collection.
PATCH /{user_id}/transactions/items-v2/{item_id}
{ main_account_id }
│
▼
User has an active float?
AND existing items already have main_account_ids set?
│ Yes
└─► Return 412 Precondition Failed
(cannot change main account while float is outstanding)
│ No
▼
Update item: main_account_id = new value
│
▼
If new main_account_id differs from other items:
Update all other items to use the new main_account_id
│
▼
Return 202 Accepted
UpdateItem v1 (PATCH /{user_id}/transactions/items/{item_id}) is deprecated. It lacks the active float guard and multi-item consistency logic.
|
Remove Item Flow
Two removal paths exist. Version 2 is preferred for all current use cases.
Remove v2 (Preferred)
DELETE /{user_id}/transactions/items-v2/{item_id}
│
▼
Item has an active float?
│ Yes
└─► Return 412 Precondition Failed
│ No
▼
Revoke access token at Plaid (RemoveItem)
│ Plaid API failure → 503 Service Unavailable
▼
Mark item status → REMOVED in DynamoDB
│
▼
Return 202 Accepted
Remove v1 (Deprecated)
Same core flow as v2, but also runs legacy employment-detection validation that can return 403 Forbidden if the user joined recently or has employment income detected. This validation was removed in v2.
Force Remove (Admin)
POST /{user_id}/transactions/items/{item_id}/remove/force
│
▼
Revoke access token at Plaid (RemoveItem)
│ Plaid API failure → 503 Service Unavailable
▼
Mark item status → REMOVED in DynamoDB
│
▼
Return 202 Accepted
Force remove bypasses all safety checks including active float validation. It is restricted to admin callers.
Change Item Check
Before the mobile app initiates a bank change via Plaid Link, it calls CheckCanChangeItem to determine whether the change is permitted.
POST /{user_id}/transactions/items/{item_id}/change/check
│
▼
Is this the main item AND user has an active float?
│ Yes
└─► Return 412 with ActiveFloatError
│ No
▼
Return 200 with CheckCanChangeItem:
{ can_be_changed, date_of_last_change,
days_until_next_change, total_wait_time }
The response includes cooldown information: in production, a 7-day cooldown (days_between_plaid_item_changes) applies after the last item change.
Remine
Remine queues an existing item for a fresh transaction and account fetch without waiting for a Plaid webhook.
POST /{user_id}/transactions/items/{item_id}/remine
│
▼
Look up item in DynamoDB
│ Not found → 404
▼
Send synthetic DEFAULT_UPDATE webhook to miner SQS
│
▼
Return 202 Accepted
Mining then proceeds through the normal Plaid Mining Pipeline.
Persist Item
An item with a TTL set will be automatically cleaned up by DynamoDB. The persist endpoint removes the TTL to prevent this.
PATCH /{user_id}/transactions/items/{item_id}/persist
│
▼
Look up item in DynamoDB
│ Not found → 404
▼
Remove TTL attribute from item record
│
▼
Return 202 Accepted
Plaid Link Token
A link token is required to initialise a Plaid Link session in the mobile app. Two endpoints exist:
-
POST /{user_id}/transactions/link— Gets a link token for a new item connection. For legacy app versions, accepts achange_bankflag that enables update mode using the existing access token. -
GET /{user_id}/transactions/items/{item_id}/link— Gets a link token in update mode for a specific existing item (to re-authenticate or add accounts).
Related Pages
-
Plaid Mining Pipeline — What happens after an item is added and the INITIAL_UPDATE webhook fires
-
Architecture — System context and Lambda breakdown
-
Features — Full Items capability reference
-
Plaid: Items — DynamoDB schema and query patterns