paybondpaybond
Sign in

Integration · Stripe

Configure Plaid bank verification

Tenant-admin guide: enable Plaid Auth as bank verification under stripe_ach_debit, link banks in Console Settlement, register /webhooks/plaid, and inspect readiness with paybond plaid ready|doctor.

  • Plaid Auth
  • stripe_ach_debit
  • /webhooks/plaid
  1. 01Connect
  2. 02Configure
  3. 03Verify
  4. 04Go live

Plaid Auth is a bank-verification input to the existing stripe_ach_debit rail — not a separate settlement rail and not Plaid Transfer. Stripe remains the ACH money mover; Harbor funds an intent only when Stripe reports payment_intent.succeeded. Operators link and fund; agents spend only after the intent is funded.

This guide is the public configuration walkthrough. Deep ops detail (env inventory, attach worker, DLQ, production canary) lives in the internal runbook for operators who deploy the gateway.

Prerequisites

  1. A Paybond tenant with Stripe ACH configured for stripe_ach_debit (see Configure settlement rails).
  2. A Plaid Dashboard app with Auth, Signal Transaction Scores, and Identity Match access; Instant Auth / Instant Match / Automated Micro-deposits on for US. Link presents the Signal risk-product disclosure and collects Identity consent where supported.
  3. Plaid ↔ Stripe Integrations linked per environment (Plaid sandbox ↔ Stripe test; Plaid production ↔ Stripe live).
  4. Gateway deploy with PLAID_AUTH_ENABLED=1, sandbox or production credentials matching PLAID_ENV, vault encryption key, and PLAID_WEBHOOK_URL pointing at https://<gateway-host>/webhooks/plaid.
  5. Tenant role that can manage or view Plaid bank link (tenant admin for Link/exchange/revoke; Harbor-readable roles may list banks).

Console workspace

Open Configuration → Settlement (/console/configuration/settlement) as a tenant admin.

From the Plaid bank verification panel you should be able to:

  • Start Plaid Link (server-created Link token; browser never receives access_token or processor tokens)
  • See linked banks with institution name, masked account, last4, status, and readiness reason
  • Retry Stripe attach when status is retryable
  • Relink when Plaid reports ITEM_LOGIN_REQUIRED (Link update mode)
  • Revoke a bank (local non-debitable first; remote /item/remove runs asynchronously)

On an ACH intent, the funding panel lets you select a ready Plaid bank or fall back to Stripe Financial Connections.

Security boundary

  • Tenant scope always comes from the authenticated session or API key — never from a tenant id in request JSON or a Plaid webhook body.
  • Console and CLI show safe metadata only (ids, masks, statuses, readiness reason codes).
  • Never paste Link tokens, access tokens, or account/routing numbers into tickets, logs, or CLI examples.
Status / reasonMeaningACH fund
readyAuth verified and Stripe bank source attachedAllowed for that bank
pending_automatic_verificationAutomated Micro-deposits in flightBlocked until Plaid verifies
attach_pending / attach_retryable / attach_failedStripe attach in progress, retryable, or failedBlocked until attach succeeds
relink_requiredRecoverable Item error (e.g. login required)Blocked until Relink
revoked / verification_expired / errorTerminal or soft-revokedBlocked
risk_check_required / risk_check_failedHigher-value ACH risk policy gateBlocked or use FC / support
feature_disabled / production_not_allowlistedDeploy flag off or tenant not allowlistedPlaid APIs return 404; use FC

Financial Connections remains the supported non-Plaid ACH path when Plaid is off, pending, or blocked.

ACH risk-policy defaults

Paybond's current NACHA 2026 risk policy screens every positive-dollar Plaid-selected ACH debit with Signal, adds a real-time Balance requirement at $500, and adds Identity Match at $1,000. The default decision cutoffs are:

ControlDefault
Identity Match legal-name scoreat least 70 / 100
Signal customer-return risk tierat most 2 / 5
Available-balance cushiondebit amount + $100
Decision freshness5 minutes

Unavailable, stale, or indeterminate results block the Plaid-selected debit; they never silently downgrade to Auth-only. Financial Connections/manual review remains the fallback. These are conservative Paybond engineering defaults—not dollar or Plaid-score thresholds prescribed by Nacha—and require Legal/Payments Risk/ODFI approval before live rollout.

The legal baseline is Nacha Article Two, Subsection 2.5.17.4 (WEB account validation, effective March 19, 2021) and the 2026 fraud-monitoring amendments (Phase 1 March 20; Phase 2 practical compliance date June 22, 2026). Plaid publishes 70 as its default recommended Identity Match threshold, but directs Signal customers to tune score/ruleset cutoffs from reported decisions and ACH returns.

Webhook URL

Register a single Paybond route with Plaid (sandbox and production share the path; environment is resolved server-side from the Item):

https://api.paybond.ai/webhooks/plaid

Or your staging/custom gateway host: https://<host>/webhooks/plaid.

Do not use a retired production-scoped webhook path segment. Use /webhooks/plaid only. The gateway verifies the Plaid-Verification JWT (ES256, body hash, iat freshness) before any durable work. AMD completion (AUTOMATICALLY_VERIFIED) enqueues Stripe attach asynchronously — webhooks never fund Harbor.

Print the address for your configured gateway:

Terminal
Terminal commandSwipe to inspect long lines
paybond plaid webhook-address
paybond plaid webhook-address --gateway https://staging.example.test

Local development: tunnel only /webhooks/plaid to your gateway, set PLAID_WEBHOOK_URL to the tunnel HTTPS URL, and never commit tunnel URLs or secrets. See the ops setup doc for the full ngrok/cloudflared recipe.

Sandbox

  1. Confirm PLAID_ENV=sandbox pairs with Stripe test keys and a sandbox tenant.
  2. Enable Auth in the gateway, set PLAID_WEBHOOK_URL (staging or tunnel).
  3. Link a sandbox Instant Auth institution in Console; list should show ready after attach.
  4. Exercise AMD with a sandbox pending institution; wait for webhook → attach worker → ready.
  5. Confirm readiness from the CLI after paybond login:
Terminal
Terminal commandSwipe to inspect long lines
paybond plaid ready
paybond plaid doctor
paybond plaid banks list

Optional deep smoke (credentials required): make plaid-auth-sandbox-smoke.

Production approval

Production stays fail-closed until ops explicitly unlocks it:

  1. Plaid production Auth approval and live Plaid ↔ Stripe Integrations link.
  2. Separate live PLAID_CLIENT_ID / PLAID_SECRET, PLAID_ENV=production, https webhook URL.
  3. PLAID_AUTH_PRODUCTION_APPROVED=1 and a non-empty PLAID_AUTH_TENANT_ALLOWLIST.
  4. Canary one tenant with Instant Auth before expanding; keep FC available.
  5. After Stripe confirms Payment Intents + Plaid bank tokens, set PLAID_STRIPE_BTOK_PI_ENABLED=1.

Kill switch: PLAID_AUTH_KILL_SWITCH=1 disables Plaid Link/list/fund with Plaid bank ids; FC ACH remains if configured.

CLI inspection (paybond plaid)

After paybond login, use the Kit CLI for read-only readiness (never Link, never tokens on argv):

Terminal
Terminal commandSwipe to inspect long lines
paybond plaid ready
paybond plaid doctor
paybond plaid banks list
paybond plaid banks get <bank-account-id>
paybond plaid webhook-address
  • plaid ready — feature available for this tenant and at least one bank with ready.
  • plaid doctor — expands ready with webhook address, environment pairing hints, and Console/docs pointers.
  • plaid banks list|get — safe bank metadata and readiness_reason only.
  • Rejected on argv: --public-token, --access-token, --link-token, --processor-token, --bank-account-token.

Next steps