Links API

A link is one connection to one financial institution, and it owns the bank accounts under it. In the app it's the thing you see in the sidebar with a bank's name on it, with the accounts nested underneath.

There are three kinds you'll actually run into. Plaid links sync from your bank on their own. Manual links are ones you maintain by hand, entering transactions and updating balances yourself. Lunch Flow links pull from a Lunch Flow instance, and only exist when that's enabled on your server.

The endpoints here create and manage manual links. Making a Plaid link is a multi-step handshake with Plaid's browser SDK that an API key can't drive, so it lives in internal endpoints.

AttributeTypeDescription
linkIdstring (ulid)Identifies the link.
linkTypestringplaid, manual, lunch_flow, or unknown.
plaidLinkobjectSync state for Plaid links, described below. Absent on every other kind.
lunchFlowLinkIdstring (ulid)The Lunch Flow link behind this one. Only on Lunch Flow links.
lunchFlowLinkobjectThe upstream Lunch Flow link. Only on Lunch Flow links.
institutionNamestringThe bank's name. On a manual link this is whatever you called it, and it's the label you see in the sidebar.
descriptionstring, nullableYour own note about the link. Null when you haven't set one.
createdAttimestampWhen the link was made.
createdBystring (ulid)The user who made it.
updatedAttimestampWhen the link last changed.
deletedAttimestamp, nullableWhen the link was removed. Always null in list responses, which filter deleted links out entirely.

Only present on Plaid links. This is where you look to find out whether a bank connection is healthy.

AttributeTypeDescription
productsarray of stringsThe Plaid products this connection was authorized for.
statusstringpending, setup, error, pending_expiration, revoked, deactivated, or unknown.
errorCodestringPlaid's error code when the connection is broken. Absent when it's fine.
expirationDatetimestamp, nullableWhen the bank's consent runs out, for institutions that expire it. Null when nothing expires.
newAccountsAvailablebooleanWhether the bank has accounts monetr knows about but you haven't added.
institutionIdstringPlaid's institution identifier, like ins_116794. This is what you pass to the institution lookup.
institutionNamestringThe institution's name according to Plaid.
lastManualSynctimestamp, nullableWhen someone last forced a sync by hand.
lastSuccessfulUpdatetimestamp, nullableWhen data last actually came through.
lastAttemptedUpdatetimestamp, nullableWhen monetr last tried to sync, successful or not. Compare against lastSuccessfulUpdate to spot a connection that's been failing quietly.
lastAccountSynctimestamp, nullableWhen monetr last checked for new accounts at the bank.
updatedAttimestampWhen the sync state last changed.
createdAttimestampWhen the Plaid connection was made.
createdBystring (ulid)The user who connected it.
deletedAttimestamp, nullableWhen it was deactivated.

The access token, item ID and webhook URL are all deliberately left out of the response.

The Lunch Flow link sub-object is documented here

Returns every link on your account. Deleted links are filtered out.

In the app: The bank sidebar, which is one of the first things the app loads.

GET /api/links

Auth: API key, subscription required.

Example

curl --request GET \
  --url "https://my.monetr.local/api/links" \
  --user "$MONETR_API_KEY_ID:$MONETR_API_KEY_SECRET"
[
  {
    "linkId": "link_01gds6ecrxq2wq8vmg2mvvv1sh",
    "linkType": "plaid",
    "plaidLink": {
      "products": ["transactions"],
      "status": "setup",
      "expirationDate": null,
      "newAccountsAvailable": false,
      "institutionId": "ins_116794",
      "institutionName": "Chase",
      "lastManualSync": null,
      "lastSuccessfulUpdate": "2024-08-27T06:00:12.418Z",
      "lastAttemptedUpdate": "2024-08-27T06:00:12.418Z",
      "lastAccountSync": "2024-08-20T06:00:09.882Z",
      "updatedAt": "2024-08-27T06:00:12.418Z",
      "createdAt": "2022-01-14T18:29:03.114Z",
      "createdBy": "user_01fpwx3sdm7kb1s0jbrbvbdw4c",
      "deletedAt": null
    },
    "institutionName": "Chase",
    "description": null,
    "createdAt": "2022-01-14T18:29:03.114Z",
    "createdBy": "user_01fpwx3sdm7kb1s0jbrbvbdw4c",
    "updatedAt": "2024-08-27T06:00:12.418Z",
    "deletedAt": null
  },
  {
    "linkId": "link_01j2n8xqvr4kd9wt3m7hbzc5pf",
    "linkType": "manual",
    "institutionName": "Credit Union",
    "description": "The joint account we never automated",
    "createdAt": "2024-07-02T13:44:51.229Z",
    "createdBy": "user_01fpwx3sdm7kb1s0jbrbvbdw4c",
    "updatedAt": "2024-07-02T13:44:51.229Z",
    "deletedAt": null
  }
]

Notice the manual link has no plaidLink key at all. It's omitted rather than null.

Returns one link.

In the app: The link details page, and the card that tells you when Plaid last updated.

GET /api/links/:linkId

Auth: API key, subscription required.

Path parameters

AttributeTypeRequiredDescription
linkIdstring (ulid)YesThe link you want.

Example

curl --request GET \
  --url "https://my.monetr.local/api/links/link_01j2n8xqvr4kd9wt3m7hbzc5pf" \
  --user "$MONETR_API_KEY_ID:$MONETR_API_KEY_SECRET"
{
  "linkId": "link_01j2n8xqvr4kd9wt3m7hbzc5pf",
  "linkType": "manual",
  "institutionName": "Credit Union",
  "description": "The joint account we never automated",
  "createdAt": "2024-07-02T13:44:51.229Z",
  "createdBy": "user_01fpwx3sdm7kb1s0jbrbvbdw4c",
  "updatedAt": "2024-07-02T13:44:51.229Z",
  "deletedAt": null
}

Unlike the list, this one will return a deleted link if you ask for it by ID, with deletedAt set.

Errors

StatusWhen
400linkId is malformed.
404No such link on your account.

Makes a link you maintain yourself. This is the starting point for tracking an account monetr can't connect to automatically: create the link, then create bank accounts on it, then add transactions. The quickstart walks the whole sequence.

In the app: Setting up a manual link, and the Lunch Flow setup flow.

POST /api/links

Auth: API key, subscription required.

Body

AttributeTypeRequiredDescription
institutionNamestringYesWhat to call the link. This is the label in the sidebar, so use the bank's name.
descriptionstring, nullableNoA note to yourself.
lunchFlowLinkIdstring (ulid), nullableNoTurns this into a Lunch Flow link instead of a manual one. The Lunch Flow link has to already exist and be in a pending status, and creating the link activates it. Leave this off unless you're wiring up Lunch Flow.

linkType is not something you send. Leave lunchFlowLinkId off and you get a manual link. Send it and you get a Lunch Flow link. Plaid links can't be made here at all.

Example

curl --request POST \
  --url "https://my.monetr.local/api/links" \
  --user "$MONETR_API_KEY_ID:$MONETR_API_KEY_SECRET" \
  --header "Content-Type: application/json" \
  --data '{
    "institutionName": "Credit Union",
    "description": "The joint account we never automated"
  }'
{
  "linkId": "link_01j2n8xqvr4kd9wt3m7hbzc5pf",
  "linkType": "manual",
  "institutionName": "Credit Union",
  "description": "The joint account we never automated",
  "createdAt": "2024-07-02T13:44:51.229Z",
  "createdBy": "user_01fpwx3sdm7kb1s0jbrbvbdw4c",
  "updatedAt": "2024-07-02T13:44:51.229Z",
  "deletedAt": null
}

Errors

StatusWhen
400institutionName is missing, or you sent a lunchFlowLinkId for a Lunch Flow link that isn't pending.
404You sent a lunchFlowLinkId on a server where Lunch Flow isn't enabled.

Renames a link or changes its description. Works on any link type, including Plaid ones, since these two fields are yours rather than the bank's.

In the app: Renaming a link or editing its description on the link details page.

PATCH /api/links/:linkId

Auth: API key, subscription required.

Path parameters

AttributeTypeRequiredDescription
linkIdstring (ulid)YesThe link to change.

Body

AttributeTypeRequiredDescription
descriptionstring, nullableNoA note to yourself, or null to clear it.
institutionNamestringNoA new name for the link.

Example

curl --request PATCH \
  --url "https://my.monetr.local/api/links/link_01j2n8xqvr4kd9wt3m7hbzc5pf" \
  --user "$MONETR_API_KEY_ID:$MONETR_API_KEY_SECRET" \
  --header "Content-Type: application/json" \
  --data '{
    "institutionName": "Lakeside Credit Union",
    "description": null
  }'
{
  "linkId": "link_01j2n8xqvr4kd9wt3m7hbzc5pf",
  "linkType": "manual",
  "institutionName": "Lakeside Credit Union",
  "description": null,
  "createdAt": "2024-07-02T13:44:51.229Z",
  "createdBy": "user_01fpwx3sdm7kb1s0jbrbvbdw4c",
  "updatedAt": "2024-08-29T20:11:03.507Z",
  "deletedAt": null
}

Errors

StatusWhen
400institutionName was sent but blank.
404No such link.

Deletes a link and everything hanging off it. This is the destructive one on this page: the bank accounts, transactions, spending objects and funding schedules underneath all go with it.

The call itself marks the link deleted and hands the rest to a background job, so it returns before the cleanup has finished. On a Plaid link it also tells Plaid to release the connection, which is why the connection stops costing you anything after this.

In the app: Removing a link, behind the confirmation prompt.

DELETE /api/links/:linkId

Auth: API key, subscription required.

Path parameters

AttributeTypeRequiredDescription
linkIdstring (ulid)YesThe link to remove.

Example

curl --request DELETE \
  --url "https://my.monetr.local/api/links/link_01j2n8xqvr4kd9wt3m7hbzc5pf" \
  --user "$MONETR_API_KEY_ID:$MONETR_API_KEY_SECRET"

Returns 200 with an empty body.

Errors

StatusWhen
400linkId is malformed, or the link is already deleted. Calling this twice is an error rather than a no-op, so monetr doesn't ask Plaid to remove the same item twice.
404No such link.