Item Lifecycle
A Plaid item is a user’s connection to one institution; it holds the access_token used for every Plaid call about that institution. A user may have several items, and one account across them is the main account used for float disbursement and subscription collection. This page is the canonical reference for item statuses and every item operation; mining is in Plaid Mining.
Item Statuses
| Status | Meaning | Set by |
|---|---|---|
|
Connected; Plaid reports no error. |
Add, prequal, and Layer creation; miner status refresh and list enrichment when Plaid reports no error |
|
Plaid reports an error on the item ( |
Miner status refresh and list enrichment when Plaid reports an error |
|
Disconnected; the access token is revoked at Plaid. |
Remove endpoints; miner on |
Source: pkg/dynamo/item.go
[ACTIVE] ──Plaid reports error──► [ERROR] [ERROR] ──Plaid clears error──► [ACTIVE] [ACTIVE] or [ERROR] ──remove, revoke, TTL expiry──► [REMOVED]
"Active" items throughout this page means status ACTIVE or ERROR.
Main-Account Rules
Add v2, update v2, and prequal apply the same rules to the requested account_id before saving. Conditions are evaluated in order.
| Condition | Result |
|---|---|
User has no active items |
Continue; activation needed |
|
|
|
Continue; no changes |
An active item has a main account and the user has an active float (Float Service) |
|
|
Clear |
|
Continue |
Source: pkg/api/items_v2.go
Post-Save Actions
Run after an item is saved by add (v1 and v2), update v2, and prequal.
-
main_account_idnon-empty: publishnew_bank_account_added(Events). Best effort; never fails the request. -
Register the webhook URL on the item at Plaid. Failure returns
500from add and prequal; update v2 logs it. -
Add paths only: enqueue a synthetic
INITIAL_UPDATEwebhook (source=FROM_ADD_ITEM) when eitheronboarding_v3(build and install id) ortxn.plaid_initial_update.synthetic_webhook(user) is enabled — GrowthBook Flags.
Add Item
POST /{user_id}/transactions/items-v2 (v2):
-
Exchange
public_tokenfor an access token and item id (Plaid); institution name from institutions. -
is_reactivating: setttlto now plusREACTIVATION_ITEM_TTL_MINS. -
Apply Main-Account Rules.
-
Save the item as
ACTIVE. -
Run Post-Save Actions.
-
Not reactivating and activation needed: activate the user (User Service).
404,409, and400from the User Service are logged; any other non-202returns500. -
201.
POST /{user_id}/transactions/items (v1) skips Main-Account Rules, activates the user before Post-Save Actions, and activates whenever neither is_reactivating nor skip_activation is set.
Prequal Item
POST /{user_id}/transactions/items/prequalify creates a temporary item for underwriting before the user commits.
-
Exchange the token and build the item as in add.
-
Set
ttlto now plusPREQUAL_ITEM_TTL_DAYS; setitem_source=PREQUAL. -
Apply Main-Account Rules; the previous main item’s
main_account_idis cleared immediately. -
Save the item as
ACTIVE; run Post-Save Actions without the synthetic webhook. -
201withitem_id. No user activation.
The caller persists the item (Persist Item) once the user proceeds; otherwise it expires (TTL Expiry). Prequal items are ACTIVE, so they appear in item lists; consumers resolving a main account skip item_source=PREQUAL.
Plaid Layer
-
POST /transactions/layer/sessionreturns a Plaid Layer session token. -
POST /transactions/layer/session/accountresolves the session’s account at Plaid and stores a Layer stub (item id and access token pairs, 7-day TTL) under thepublic_token. -
POST /{user_id}/transactions/layer/session/accountcreates oneACTIVEitem per stub entry (no main account) and enqueues a syntheticHISTORICAL_UPDATE(source=FROM_LAYER_STUB) for each.
A stub whose TTL expires before step 3 is disconnected at Plaid by the feeder — Feeder.
Update Item
PATCH /{user_id}/transactions/items-v2/{item_id} (v2):
-
Fetch the item by id;
404if absent. -
Apply Main-Account Rules.
-
Set
main_account_id; write aplaid-account-changesrow holding the previous account; publish theaudit-logevent. -
Run Post-Save Actions without the synthetic webhook.
-
202.
PATCH /{user_id}/transactions/items/{item_id} (v1) performs step 3 only, then publishes primary_bank_account_changed when the new id is non-empty. It has no float guard and does not clear other items' main accounts.
Remove Item
DELETE /{user_id}/transactions/items-v2/{item_id} (v2):
-
Fetch by user and item; not found or already
REMOVED:202. -
Item has a main account and the user has an active float:
412. -
Revoke the access token at Plaid; any Plaid error other than item-not-found returns
503. -
Set
REMOVED; write aplaid-account-changesrow;202.
DELETE /{user_id}/transactions/items/{item_id}/remove (v1) adds a ban check between steps 2 and 3: a user who joined less than MINUTES_BEFORE_PLAID_ITEM_CHANGE ago and has employment detected (Insight Service) is banned (User Service, or logged only when LOG_ONLY_PLAID_ITEM_BAN), sent the Iterable event conAccts_plaid_item_changed, and gets 403.
POST /{user_id}/transactions/items/{item_id}/remove/force skips the float check and records item_removed_reason=MX.
Listing items enriches each from Plaid. An item Plaid reports as not found is set REMOVED during the GET.
|
Change Check
POST /{user_id}/transactions/items/{item_id}/change/check tells the app whether the user may switch banks. Conditions are evaluated in order.
| Condition | Response |
|---|---|
Item not found, has no main account, or is |
|
User has an active float |
|
|
|
No |
|
Last change plus |
|
Otherwise |
|
Persist Item
PATCH /{user_id}/transactions/items/{item_id}/persist clears ttl on the item (404 if absent) and returns 202.
Remine
POST /{user_id}/transactions/items/{item_id}/remine enqueues a synthetic HISTORICAL_UPDATE (source=API_REMINE) for an existing item (404 if absent) and returns 202.
TTL Expiry
Items carry a ttl when added with is_reactivating or through prequal. When DynamoDB expires the row, the feeder sets REMOVED with item_removed_reason naming the incomplete flow and revokes the token at Plaid, unless it is a prequal item of a user who is already an active member — Feeder.
Link Tokens
-
POST /{user_id}/transactions/linkreturns a Link token for a new connection. A missing body returns400; a user whose status isDENIED,INVESTIGATE,INACTIVE,OTHER, orTEST(User Service) returns400. Withchange_bank, the token is created in update mode against the user’s first active item. -
New-connection tokens request
transactions(withtransactions.days_requested180), optionalauth, and additional consentedliabilities. Plaid Layer sessions take their history depth from the Layer template on the Plaid dashboard. -
GET /{user_id}/transactions/items/{item_id}/linkreturns an update-mode token for one item; theupdatequery parameter requests account-selection update mode. -
POST /{user_id}/transactions/admin/items/{item_id}/reset-login(test only) resets a sandbox item toITEM_LOGIN_REQUIRED.