> ## Documentation Index
> Fetch the complete documentation index at: https://docs.encoreos.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Plaid Sandbox Verification

> Purpose: Verify Plaid Transfer and Transfer UI against Plaid Sandbox (no real banks). Use for manual or CI runs when Sandbox credentials are available.

**Purpose:** Verify Plaid Transfer and Transfer UI against Plaid Sandbox (no real banks). Use for manual or CI runs when Sandbox credentials are available.

**See also:** [FA-20 Plaid Integration](/architecture/integrations/plaid-integration)

***

## Environment

Set these for Sandbox:

| Variable                       | Purpose                                                         |
| ------------------------------ | --------------------------------------------------------------- |
| `PLAID_ENVIRONMENT`            | `sandbox`                                                       |
| `PLAID_CLIENT_ID`              | From Plaid Dashboard                                            |
| `PLAID_SECRET`                 | From Plaid Dashboard (Sandbox)                                  |
| `PLAID_ORIGINATION_ACCOUNT_ID` | From Plaid Dashboard → Transfer → Origination account (Sandbox) |

For **Transfer UI**, in Plaid Dashboard create a Link customization with **Account Select: Enabled for one account**. Optionally set `plaid_link_customization_name` in `fa_module_settings` per org (or pass from frontend via `TransferUIButton` / `useTransferUI`).

***

## Payroll (programmatic) flow

* Use Sandbox credentials in the edge function (or local env when running functions locally).
* In Sandbox, **transfers stay `pending`** until you simulate via [Plaid Dashboard](https://dashboard.plaid.com/) or API.
* **Automatic state transition:** Use amount **\$11.11** to trigger automatic progression: pending → posted → settled → funds available for ACH debits. See [Plaid Transfer Sandbox – Automatic Sandbox simulations](https://plaid.com/docs/transfer/sandbox/).
* **Webhooks:** In Sandbox, **webhooks do not fire** unless you call `POST /sandbox/transfer/fire_webhook`. For payroll webhook testing, use that endpoint to simulate the webhook after simulating transfer status in the Dashboard.

***

## Transfer UI flow

1. **Create intent:** Call `plaid-transfer-intent-create` with `organization_id`, `mode`, `amount`, `description`, `ach_class`, `user`. Backend uses Sandbox and returns `transfer_intent_id`. **Note:** The `description` parameter is subject to Plaid’s maximum length (8 characters for underlying transfers). Validate or truncate the description client- or server-side before calling this endpoint to avoid Sandbox validation errors.
2. **Link token:** Call `plaid-create-link-token` with `organization_id` and `transfer_intent_id` (and optional `link_customization_name`). Receive `link_token`.
3. **Open Link:** In the app, open Plaid Link with that token. In Sandbox use **First Platypus Bank** and test user to complete the flow.
4. **Confirm:** Call `plaid-transfer-intent-get` with `organization_id` and `transfer_intent_id` to confirm `status` and `transfer_id`.

***

## Optional: Script and conditional integration test

* **Script:** Run `scripts/plaid-sandbox-verify.ts` when `PLAID_SANDBOX_TESTS=1` and Supabase + Plaid Sandbox env vars are set. It invokes `plaid-transfer-intent-create` then `plaid-transfer-intent-get` and logs success/failure for manual verification.
* **Conditional integration test:** In `tests/integration/fa/plaid-transfer-intent-create.test.ts`, the test "create then get (Sandbox) when PLAID\_SANDBOX\_TESTS=1 and credentials set" runs only when `PLAID_SANDBOX_TESTS=1` and `PLAID_CLIENT_ID`, `PLAID_SECRET`, `PLAID_ORIGINATION_ACCOUNT_ID` are set. It creates an intent then calls intent-get and asserts a 200 response. CI without Sandbox secrets skips this test.

***

## Checklist (manual)

* [ ] Set `PLAID_ENVIRONMENT=sandbox`, `PLAID_CLIENT_ID`, `PLAID_SECRET`, `PLAID_ORIGINATION_ACCOUNT_ID`.
* [ ] (Transfer UI) Create Link customization with Account Select for one account; set `plaid_link_customization_name` if desired.
* [ ] (Payroll) Use amount \$11.11 for automatic state transition; use Dashboard or `POST /sandbox/transfer/fire_webhook` for webhook testing.
* [ ] (Transfer UI) Create intent → get link token → open Link in Sandbox (First Platypus Bank) → complete flow → call intent-get to confirm status/transfer\_id.
