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
- A Paybond tenant with Stripe ACH configured for
stripe_ach_debit(see Configure settlement rails). - 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.
- Plaid ↔ Stripe Integrations linked per environment (Plaid sandbox ↔ Stripe test; Plaid production ↔ Stripe live).
- Gateway deploy with
PLAID_AUTH_ENABLED=1, sandbox or production credentials matchingPLAID_ENV, vault encryption key, andPLAID_WEBHOOK_URLpointing athttps://<gateway-host>/webhooks/plaid. - 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_tokenor 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/removeruns 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.
Link and verification statuses
| Status / reason | Meaning | ACH fund |
|---|---|---|
ready | Auth verified and Stripe bank source attached | Allowed for that bank |
pending_automatic_verification | Automated Micro-deposits in flight | Blocked until Plaid verifies |
attach_pending / attach_retryable / attach_failed | Stripe attach in progress, retryable, or failed | Blocked until attach succeeds |
relink_required | Recoverable Item error (e.g. login required) | Blocked until Relink |
revoked / verification_expired / error | Terminal or soft-revoked | Blocked |
risk_check_required / risk_check_failed | Higher-value ACH risk policy gate | Blocked or use FC / support |
feature_disabled / production_not_allowlisted | Deploy flag off or tenant not allowlisted | Plaid 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:
| Control | Default |
|---|---|
| Identity Match legal-name score | at least 70 / 100 |
| Signal customer-return risk tier | at most 2 / 5 |
| Available-balance cushion | debit amount + $100 |
| Decision freshness | 5 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.
- Nacha WEB account validation
- Nacha Fraud Monitoring Phase 2
- Plaid Identity Match scores
- Plaid Signal tuning
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
paybond plaid webhook-address
paybond plaid webhook-address --gateway https://staging.example.testLocal 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
- Confirm
PLAID_ENV=sandboxpairs with Stripe test keys and a sandbox tenant. - Enable Auth in the gateway, set
PLAID_WEBHOOK_URL(staging or tunnel). - Link a sandbox Instant Auth institution in Console; list should show
readyafter attach. - Exercise AMD with a sandbox pending institution; wait for webhook → attach worker →
ready. - Confirm readiness from the CLI after
paybond login:
terminal
paybond plaid ready
paybond plaid doctor
paybond plaid banks listOptional deep smoke (credentials required): make plaid-auth-sandbox-smoke.
Production approval
Production stays fail-closed until ops explicitly unlocks it:
- Plaid production Auth approval and live Plaid ↔ Stripe Integrations link.
- Separate live
PLAID_CLIENT_ID/PLAID_SECRET,PLAID_ENV=production, https webhook URL. PLAID_AUTH_PRODUCTION_APPROVED=1and a non-emptyPLAID_AUTH_TENANT_ALLOWLIST.- Canary one tenant with Instant Auth before expanding; keep FC available.
- 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
paybond plaid ready
paybond plaid doctor
paybond plaid banks list
paybond plaid banks get <bank-account-id>
paybond plaid webhook-addressplaid ready— feature available for this tenant and at least one bank withready.plaid doctor— expands ready with webhook address, environment pairing hints, and Console/docs pointers.plaid banks list|get— safe bank metadata andreadiness_reasononly.- Rejected on argv:
--public-token,--access-token,--link-token,--processor-token,--bank-account-token.
Next steps
-
Fund an ACH intent with a ready bank or Financial Connections: Fund intents by rail.
-
Broader rail configuration: Configure settlement rails.
-
Agent spend after funding: Protect Stripe payments from agents.
Configure settlement rails
Fund intents by rail
Settlement with payment providers