curl --request GET \
--url https://sandbox.layerfi.com/v1/businesses/{businessId}/plaid/connection-events \
--header 'Authorization: Bearer <token>'import requests
url = "https://sandbox.layerfi.com/v1/businesses/{businessId}/plaid/connection-events"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://sandbox.layerfi.com/v1/businesses/{businessId}/plaid/connection-events', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://sandbox.layerfi.com/v1/businesses/{businessId}/plaid/connection-events",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://sandbox.layerfi.com/v1/businesses/{businessId}/plaid/connection-events"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://sandbox.layerfi.com/v1/businesses/{businessId}/plaid/connection-events")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://sandbox.layerfi.com/v1/businesses/{businessId}/plaid/connection-events")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"data": [
{
"type": "Plaid_Connection_Event",
"id": "9340d882-75cc-4224-9820-cc8634856d84",
"event_type": "LINK_EXCHANGE_FAILED",
"source": "USER",
"actor": "USER",
"connection_type": null,
"connection_id": null,
"plaid_account_id": null,
"webhook_type": null,
"webhook_code": null,
"details": "PlaidExchangePublicTokenError",
"created_at": "2026-11-01T12:00:00Z"
}
],
"meta": {
"pagination": {
"sort_by": "created_at",
"sort_order": "DESC",
"cursor": "opaque-cursor",
"has_more": false,
"total_count": 1
}
}
}List Plaid connection events
List recorded Plaid connection events for a business, newest first by default.
curl --request GET \
--url https://sandbox.layerfi.com/v1/businesses/{businessId}/plaid/connection-events \
--header 'Authorization: Bearer <token>'import requests
url = "https://sandbox.layerfi.com/v1/businesses/{businessId}/plaid/connection-events"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://sandbox.layerfi.com/v1/businesses/{businessId}/plaid/connection-events', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://sandbox.layerfi.com/v1/businesses/{businessId}/plaid/connection-events",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://sandbox.layerfi.com/v1/businesses/{businessId}/plaid/connection-events"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://sandbox.layerfi.com/v1/businesses/{businessId}/plaid/connection-events")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://sandbox.layerfi.com/v1/businesses/{businessId}/plaid/connection-events")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"data": [
{
"type": "Plaid_Connection_Event",
"id": "9340d882-75cc-4224-9820-cc8634856d84",
"event_type": "LINK_EXCHANGE_FAILED",
"source": "USER",
"actor": "USER",
"connection_type": null,
"connection_id": null,
"plaid_account_id": null,
"webhook_type": null,
"webhook_code": null,
"details": "PlaidExchangePublicTokenError",
"created_at": "2026-11-01T12:00:00Z"
}
],
"meta": {
"pagination": {
"sort_by": "created_at",
"sort_order": "DESC",
"cursor": "opaque-cursor",
"has_more": false,
"total_count": 1
}
}
}Access
Use a platform access token for the business’s client or a business-scoped token for that business.Interpret the fields
event_typeanddetailsdescribe what happened. Start with the event types below to distinguish failures from normal activity.connection_typeandconnection_ididentify a Layer item or processor-token record.plaid_account_idis a Layer account UUID. These are not Plaid IDs or token values.sourceandactorshow the event’s origin and recorded actor;actorcan be absent.created_atis when Layer recorded it.webhook_typeandwebhook_codeidentify a Plaid notification. Read them alongsidedetailsbefore deciding whether it reports an error.
connection_id is absent, investigate using the business and created_at.
Event types
Link and connection setup
LINK_TOKEN_CREATED— Normal setup. Layer created a Link token.detailsisstandardorupdate; update mode includes the existing connection ID. This does not mean the user connected an account.LINK_CLIENT_OUTCOME— Client report.detailscontainsCOMPLETED,EXITED, orERROR, optionally followed by:error_code, such asEXITED:INVALID_CREDENTIALS. An exit can be cancellation, not a failure.COMPLETEDis not confirmation of token exchange or sync. These events have no connection ID.LINK_EXCHANGE_SUCCEEDED— Exchange succeeded. Layer exchanged the public token and added the item. Useconnection_idto follow later sync events; synchronization can still fail.LINK_EXCHANGE_FAILED— Exchange failed.detailscontains the exception class name, not necessarily Plaid’s underlying error code. No connection ID is recorded; use the business, timestamp, and exception name to investigate.LINK_UPDATE_COMPLETED— Update notification. The client called Layer’s connection-status update endpoint. Layer records this business-level event before syncing; it does not confirm repair or successful sync. No connection ID is recorded.PROCESSOR_TOKEN_ATTACHED— Normal setup. Layer stored a processor token for the business. Useconnection_idto follow that token’s events. Attachment does not confirm that the token can sync.
Sync, webhooks, and repair
WEBHOOK_RECEIVED— Notification received. Not inherently an error. Checkwebhook_typeandwebhook_code;detailscan contain JSON text with an error, reason, disconnect time, or consent-expiration time. Use the connection and account IDs to locate the affected records. Receipt does not confirm successful processing.SYNC_FAILED— Synchronization failed.detailscontains JSON text with the exception name and, when available, Plaid error information, HTTP status, or endpoint. Investigate the connection ID and these diagnostics; a sync failure alone does not establish that credentials need repair.CONNECTION_NEEDS_REPAIR— Repair required. Layer marked the connection or account as needing repair.detailscan bepersistent, but is not a root-cause code. Checksource, the connection/account IDs, and nearby webhook or sync errors for context.CONNECTION_REPAIRED— Repair state cleared. Layer cleared the connection’s repair flag. Usesourceandconnection_idto investigate the transition. This does not guarantee that all data has synchronized.
Connection lifecycle
CONNECTION_ARCHIVED— Lifecycle change. Layer archived an item or processor-token record. Checkactor,source, andconnection_id; archival can also follow a disconnect or account archival.CONNECTION_DISCONNECTED— Lifecycle change. Layer marked an item as disconnected and then archives it. Useconnection_idto follow the related archive event.CONNECTION_REACTIVATED— Lifecycle change. Layer cleared an item’s or processor token’s archived state. Checksource,actor, andconnection_id; reactivation alone does not confirm healthy credentials or successful sync.
Filter and paginate
Useevent_types=LINK_EXCHANGE_FAILED,SYNC_FAILED to focus on exchange and sync failures.
Omit event_types when you need surrounding lifecycle events. Filters combine with AND; the event_types values match any listed type.
Filtering by a connection or account excludes events that have no matching ID.
Results default to newest first. While meta.pagination.has_more is true, pass meta.pagination.cursor with the same filters and sort parameters.
A cursor can still be present on the last page. Set show_total_count=true to include the total number of matching events.Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Path Parameters
Layer business UUID. Platform credentials can access businesses belonging to their client; business credentials can access their own business.
Query Parameters
Filter by connection kind. Filters combine with AND; events with no connection kind will not match.
ITEM, PROCESSOR_TOKEN Layer UUID of the Plaid item or processor-token record, not Plaid's item ID or a token value.
Layer UUID of the Plaid account. Matches events explicitly associated with that account, not all events for its connection.
Filter by case-sensitive event types, comma-separated or repeated. See Event types for diagnostic guidance.
Recorded event kind. See Event types for diagnostic guidance.
LINK_TOKEN_CREATED, LINK_EXCHANGE_SUCCEEDED, LINK_EXCHANGE_FAILED, LINK_CLIENT_OUTCOME, LINK_UPDATE_COMPLETED, WEBHOOK_RECEIVED, SYNC_FAILED, CONNECTION_NEEDS_REPAIR, CONNECTION_REPAIRED, PROCESSOR_TOKEN_ATTACHED, CONNECTION_ARCHIVED, CONNECTION_DISCONNECTED, CONNECTION_REACTIVATED Maximum number of events per page.
1 <= x <= 1000Pass meta.pagination.cursor from the previous page while has_more is true. Keep filters and sort parameters unchanged.
created_at Order by created_at. Ties are ordered by event UUID ascending in either direction.
ASC, DESC Include the total number of matching events across all pages in meta.pagination.total_count.