Skip to main content

Payment Integrations

Payment Integrations

Component File: src/features/admin/components/PaymentIntegrations.tsx Route / navigation: Path /administration, Zustand administrationTool = payment-integrations. See 00-ADMINISTRATION-HUB.md. Access Level: Parent Org Only Last Updated: March 27, 2026 Status: ✅ Implemented

Overview

Payment Integrations helps parent organization admins connect Stripe so online gifts can settle to the nonprofit’s bank account. The setup row exposes three actions: Create new Stripe account (Express accounts.create when no Connect is resolved on the ancestor chain, otherwise resume onboarding—including Standard accounts, which skip Stripe Account Links and return without a new tab), Connect Stripe account (dialog; existing_stripe_account_id for Express / Standard / Custom connected accounts on the platform; Standard saves immediately, then Check connection), and Check connection. Routing and application fees are handled by existing checkout/payment Edge Functions after the org row has stripe_account_id.

Strings: User-visible text lives under admin.paymentIntegrationsPage in src/i18n/locales/*/auth.json (including `stripeInvalidRequest`, `connectCreateFailedGeneric` for clearer Connect setup toasts).

Access Control

> ⚠️ PARENT ORG ONLY: This tool is restricted to users with the parent_org role. Fund users do NOT have access.

| User Type | Access |
|-----------|--------|
| **Parent Org (`parent_org`)** | ✅ Full access |
| **Fund User (`fund_user`)** | ❌ No access |
| **Staff** | ❌ No access |

Supported processor

| Processor | Status | Notes |
|-----------|--------|--------|
| **Stripe (Connect Express)** | ✅ Active | Only supported path for donation processing in this screen |

When `legacy_direct` applies (no Connect on the ancestor chain but the org is under `DIRECT_STRIPE_PAYOUT_ORG_ID`), the status card still reflects platform account details from Stripe—same as checkout routing. See STRIPE-SETUP-GUIDE.md § *Shared payment routing*.

UI (high level)

  • Centered primary card: One centered setup/status card with a compact action row.
  • Setup tile/card behavior: Three buttons only—Create new Stripe account, Connect Stripe account (modal with acct_…), Check connection—plus parent-only gating and legacy/migration alerts as today.
  • Status tile: Separates ready, in progress, finishing setup (webhook propagation lag), and needs attention.
  • Actions: Check connection, Continue setup, Payout dashboard, Update bank details, Sync now, and History (state-dependent).
  • No manual test button: Replaced by Check connection + automatic refetch on focus/return/pending intervals.

Stripe integration (technical)

Uses checkStripeConnection(), createStripeConnectOrganization, createStripeConnectAccountLink, syncStripeSubscriptions, fetchSyncLogs, and related Edge Functions. See STRIPE-SETUP-GUIDE.md and STRIPE-CONNECT-UPGRADE.md.

Connection status vs checkout: The `check-stripe-connection` Edge Function uses the same `resolvePaymentTargetForOrg` logic as `create-payment-intent`, `create-checkout-session`, and `create-event-checkout`. Child funds under a parent with Connect (or under `DIRECT_STRIPE_PAYOUT_ORG_ID` for `legacy_direct`) see `active` / `connect_mode` consistent with whether online card payments can be created—not only whether the current org row has stripe_account_id.

const status = await checkStripeConnection(organizationId);
// Returns: { connected, status, account, error, lastChecked, ... }
await syncStripeSubscriptions(paymentCheckOrgUuid); // org UUID scope
const logs = await fetchSyncLogs('stripe', 20); // reads sync_logs

Notes

  • checkStripeConnection(organizationId?) accepts an optional org UUID; this page passes paymentCheckOrgUuid for tenant-scoped checks.
  • Sync is organization-scoped (organization_id) and should never send Stripe account IDs (acct_...) as the sync input.
  • Sync history in the dialog comes from sync_logs via fetchSyncLogs('stripe', 20).
  • Express actions (“Express Dashboard”, “Update bank details”) are shown when connect_mode === 'express'. `legacy_direct` is not shown as green “Connected”: when `REQUIRE_STRIPE_CONNECT_FOR_DONATIONS` is on (default), `check-stripe-connection` returns `needs_connect` with `legacy_direct_blocked` (same rule as donation/event checkout). If ops sets `REQUIRE_STRIPE_CONNECT_FOR_DONATIONS=false`, the UI shows Platform account with a warning until Connect is completed.
  • Stripe onboarding returns to /admin/stripe-onboarding and the app routes users back to Administration → Payment Integrations automatically.
  • Connect setup failures map structured error codes from create-stripe-connect-account (connect_not_enabled, already_connected, stripe_resume_account_missing, invalid_account_id, stripe_account_not_found, unsupported_account_type, stripe_account_already_linked, database_error, permission_denied, missing_authorization, invalid_authorization, method_not_allowed, connect_create_failed, `stripe_invalid_request`, etc.) so the UI can show actionable customer-safe messages (API `message` preferred when present).
  • Stripe platform-not-enabled onboarding failures are explicitly mapped to connect_not_enabled (based on Stripe message pattern), avoiding misleading generic setup errors.
  • The client error adapter now assigns stable fallback codes for non-JSON/network invoke failures (instead of showing a generic unknown error).
  • Unknown setup failures include a customer-safe support reference timestamp in the toast for easier ops triage.
  • Readiness is intentionally conservative: UI treats the connection as fully ready when Stripe account status is active and org DB flags (stripe_charges_enabled) are updated by platform-webhook.

Related documentation


Synced from IFMmvp-Frontend documentation: pages/administration/03-PAYMENT-INTEGRATIONS.md

Ready to Get Started?

See how Alignmint can simplify your nonprofit's operations. Schedule a free demo with our team and we'll walk you through everything.

Questions? Email us at steven@getalignmint.org

Ready to get started?Start Plus Trial