Plaid Integration

Connect bank accounts through Plaid for automatic transaction syncing.

Where this fits in the API. The easiest way to connect a bank is the Integrations page in the DayZero dashboard, which drives the flow below for you. The /api/v1/plaid/* endpoints are callable with an API token but are not part of the public API Reference — they exist to support DayZero's own UI and may change. Once a bank is connected, its data appears through the public Transactions and Ledgers endpoints, which is where integrations should read from.

Connect a Bank Account

There are two flows. Hosted Link needs no frontend code: DayZero returns a Plaid-hosted URL (and emails it to the recipient) where the account holder logs in to their bank.

bash
curl -X POST "https://api.ondayzero.com/api/v1/plaid/hosted-link" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID" \
  -H "Content-Type: application/json" \
  -d '{ "email": "owner@acme.com", "completion_redirect_uri": "https://app.example.com/connected" }'

Plaid's webhook completes the connection; poll GET /api/v1/plaid/pending-connection-requests and GET /api/v1/plaid/connections to see it arrive.

Embedded Link is for your own UI using react-plaid-link (or another Plaid Link SDK):

  1. Mint a Link token — the response has a link_token for the SDK and a connection_request_id to echo back:

    bash
    curl -X POST "https://api.ondayzero.com/api/v1/plaid/link-token" \
      -H "Authorization: Bearer dz_your_token_here" \
      -H "x-business-id: YOUR_BUSINESS_ID" \
      -H "Content-Type: application/json" \
      -d '{}'
  2. Open Plaid Link with the link_token.

  3. In the SDK's onSuccess callback, exchange the public token:

    bash
    curl -X POST "https://api.ondayzero.com/api/v1/plaid/exchange-public-token" \
      -H "Authorization: Bearer dz_your_token_here" \
      -H "x-business-id: YOUR_BUSINESS_ID" \
      -H "Content-Type: application/json" \
      -d '{
        "public_token": "public-sandbox-...",
        "connection_request_id": "CONNECTION_REQUEST_UUID",
        "institution_id": "ins_3",
        "institution_name": "Chase"
      }'

Choose Which Accounts to Sync

A connection can expose several accounts (checking, savings, a card). Pick the ones to sync and, optionally, map each to an existing ledger or set how far back to import:

bash
curl -X POST "https://api.ondayzero.com/api/v1/plaid/link-selected-accounts" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "connection_id": "CONNECTION_UUID",
    "plaid_account_ids": ["PLAID_ACCOUNT_ID"],
    "entries_start": "2026-01-01"
  }'

Each linked account becomes a bank ledger (with financial_account_type: bank_account or credit_card) that transactions flow into. To reuse an existing ledger instead of creating a new one, list the eligible ones with GET /api/v1/plaid/ledger-candidates?plaid_account_type=depository (depository → asset ledgers; credit or loan → liability ledgers) and pass "ledger_assignments": {"PLAID_ACCOUNT_ID": "LEDGER_UUID"} when linking. Ledgers with a reconciliation in progress cannot be changed until it completes.

Transaction Syncing

Once connected, transactions sync automatically. New transactions are:

  1. Imported with raw bank descriptions (source: plaid)
  2. Cleaned (merchant name normalization into counterparty)
  3. Auto-categorized using AI and user-defined bank rules
  4. Available for review in GET /api/v1/transactions — see Transactions

POST /api/v1/plaid/refresh-balances refreshes cached account balances on demand.

Reauthorization

Bank connections occasionally require reauthorization (e.g., when a bank requires re-login or MFA). DayZero tracks these events — the connection's sync_status and error_code show it in GET /api/v1/plaid/connections — and prompts users in the dashboard. Programmatically, POST /api/v1/plaid/reauthorize-connection with {"connection_id": "…"} returns a fresh Hosted Link URL, or pass connection_id to /plaid/link-token for an update-mode embedded token.

List Connected Accounts

bash
curl "https://api.ondayzero.com/api/v1/plaid/connections" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID"

Returns every bank connection with its institution, status and accounts. GET /api/v1/plaid/bank-accounts lists the linked accounts with their cached balances. The same connection summary is embedded on each business as plaid_connections in GET /api/v1/businesses.

Disconnect

Preview the impact first — unlinking stops syncing and can affect ledgers that only exist because of the feed:

bash
curl -X POST "https://api.ondayzero.com/api/v1/plaid/account/unlink-preview" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID" \
  -H "Content-Type: application/json" \
  -d '{"connection_id": "CONNECTION_UUID", "plaid_account_id": "PLAID_ACCOUNT_ID"}'

Then POST /api/v1/plaid/account/unlink with the same body (plus confirm_phrase — the linked ledger's exact name — when the preview reports linked ledgers) to stop syncing one account, or DELETE /api/v1/plaid/connection with {"connection_id": "…"} to remove the whole bank connection (POST /api/v1/plaid/connection/delete-preview first). Already-imported transactions stay in the books.