> ## 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.

# Gusto Embedded Payroll - Integration Documentation

> Feature ID: PF-65 Status: 📝 Planned Created: 2026-02-05 Version: v1.0.0 Spec Reference: specs/pf/specs/PF-65-gusto-embedded-payroll-integration.md (v1.0)

**Feature ID:** PF-65\
**Status:** 📝 Planned\
**Created:** 2026-02-05\
**Version:** v1.0.0\
**Spec Reference:** `specs/pf/specs/PF-65-gusto-embedded-payroll-integration.md` (v1.0)

***

## Overview

PF-65 provides a **Platform Integration Layer** for the Gusto Embedded React SDK (`@gusto/embedded-react-sdk`). It enables HR (and other cores) to embed Gusto payroll and onboarding workflows inside Encore Health OS without implementing auth or proxy logic. All SDK traffic goes through a **backend proxy** (Supabase Edge Function) that adds OAuth2 tokens and `x-gusto-client-ip`.

***

## Integration Patterns

| Type           | Pattern                 | Location                                                 | Status     |
| -------------- | ----------------------- | -------------------------------------------------------- | ---------- |
| Platform Layer | Pattern 1               | `@/platform/gusto` (or equivalent)                       | 📝 Planned |
| Backend Proxy  | API (internal)          | Supabase Edge Function `gusto-proxy`                     | 📝 Planned |
| PF-35          | Credential storage      | `pf_integrations` (integration\_type `gusto_embedded`)   | 📝 Planned |
| HR consumer    | Platform Layer consumer | HR routes under `/hr/payroll/gusto`, `/hr/me/onboarding` | 📝 Planned |

***

## Platform Integration Layer

**Location:** `/src/platform/gusto/` (to be created)

**Public API (from spec):**

```typescript theme={null}
// Re-exports from @gusto/embedded-react-sdk (configured).
// Note: Gusto docs use Employee.EmployeeList; verify package exports (top-level EmployeeList vs Employee.EmployeeList) at implementation.
export { GustoProvider, EmployeeOnboardingFlow, EmployeeList, componentEvents } from '@gusto/embedded-react-sdk';

export function useGustoConfig(): {
  baseUrl: string;
  companyId: string | null;
  isConnected: boolean;
  isLoading: boolean;
  error: Error | null;
};

export function useGustoConnectionStatus(organizationId: string): {
  status: 'connected' | 'disconnected' | 'error';
  gustoCompanyId: string | null;
  isLoading: boolean;
};
```

**Usage (HR consumer):**

```typescript theme={null}
import { GustoProvider, EmployeeOnboardingFlow, useGustoConfig } from '@/platform/gusto';

function HRGustoOnboardingPage() {
  const { baseUrl, companyId, isConnected, isLoading, error } = useGustoConfig();
  if (!isConnected || !companyId) return <EmptyState />;
  return (
    <GustoProvider config={{ baseUrl }}>
      <EmployeeOnboardingFlow companyId={companyId} onEvent={handleEvent} />
    </GustoProvider>
  );
}
```

**Permissions:** `hr.gusto.view` (embed components), `hr.gusto.configure` (configure connection and company mapping).

***

## API Contract: Gusto Proxy

**Endpoint:** Supabase Edge Function, e.g. `POST /functions/v1/gusto-proxy`

**Behavior:**

* Receives request from SDK (path + body match Gusto Embedded API 1:1).
* Resolves authenticated user’s `organization_id`; loads that org’s Gusto OAuth access token from PF-35 (`pf_integrations` + credentials).
* Adds `Authorization: Bearer <token>` and `x-gusto-client-ip` (from `X-Forwarded-For` or `X-Real-IP`).
* Forwards to `https://api.gusto.com` (exact path per Gusto Embedded API docs).
* On 401: attempts token refresh (using stored refresh token). If the authorization server returns a **new refresh token** in the refresh response, the proxy **must persist and replace** the old refresh token in the credential store (PF-35 / `pf_integrations`) so future refreshes use the new value. The retry MUST use the newly issued **access token** in the `Authorization: Bearer <token>` header. On refresh or persist failure, return a sanitized error (e.g. 502 "Reconnect to Gusto") without exposing tokens.

**Request (from client):** Transparent pass-through; client sends same path/body as to Gusto API. Proxy does not alter body.

**Response:** Same as Gusto API response; errors sanitized (no tokens or stack traces).

**Error codes:** Document in `API_CONTRACTS.md` (e.g. 401 Unauthorized, 502 Bad Gateway, 503 Service Unavailable).

***

## Security

* OAuth tokens and refresh tokens **only server-side** (PF-35 / Vault); never in frontend.
* **`x-gusto-client-ip` (trusted client IP):** The Edge Function (or middleware) must derive a trusted client IP as follows:
  * Prefer **X-Forwarded-For**: use the **rightmost** entry added by your trusted edge proxy (i.e., the last IP in the chain), since the leftmost is typically the original client and the rightmost is the one added by the proxy closest to this service.
  * Fall back to **X-Real-IP** only if the request is known to have passed through a trusted proxy that sets it.
  * Otherwise use the connection **remote address**.
  * The Edge Function must **validate/sanitize** the chosen IP: parse and canonicalize it, reject private/reserved ranges unless explicitly expected (e.g., internal networks), and verify the request passed through a known proxy list when using forwarded headers. If no trusted IP can be determined, set the header value to **"unknown"** and log a warning.
* Proxy and company resolution **scoped by `organization_id`**; no cross-tenant data.

***

## SDK Event Types

The Gusto Embedded SDK emits events via `onEvent` callback. Encore Health OS handles:

| Event Name            | Description                  | Encore Health OS Action       |
| --------------------- | ---------------------------- | ----------------------------- |
| `employee/created`    | New employee added to Gusto  | Toast notification, analytics |
| `onboarding/complete` | Employee finished onboarding | Toast notification, analytics |

**Full Event Reference:** See [Gusto Embedded SDK Documentation](https://docs.gusto.com/embedded-payroll/docs/embedded-events)

***

## References

* **Spec:** `specs/pf/specs/PF-65-gusto-embedded-payroll-integration.md`
* **PF-35:** Integration Hub – `specs/pf/specs/PF-35-integration-hub.md`
* **API Contracts:** `docs/architecture/integrations/API_CONTRACTS.md` (proxy to be added)
* **Platform Integration Layers:** `docs/architecture/integrations/PLATFORM_INTEGRATION_LAYERS.md`
* **Gusto Embedded API:** [https://docs.gusto.com/embedded-payroll/docs/](https://docs.gusto.com/embedded-payroll/docs/)
