Version: 2.1.4Documentation Index
Fetch the complete documentation index at: https://docs.encoreos.io/llms.txt
Use this file to discover all available pages before exploring further.
Last Updated: 2026-05-18
Constitution Reference: Section 1.3 (Integration Patterns - Pattern 3) API Contracts provide synchronous request-response interactions between cores. These are REST APIs for direct data queries between cores when event-driven patterns are not suitable.
API Contract Standards
All API contracts MUST follow:- Versioning:
/api/v1/{core}/{resource} - Authentication: JWT auth with RLS enforcement
- Rate Limiting: Per-organization limits
- Error Handling: Standard HTTP status codes
- Response Format: JSON with consistent structure
Machine / organization API access (PF-97)
Interactive users authenticate with Supabase Auth JWTs; callers validateorganization_id against session membership (pf_user_role_assignments / pf_has_org_access) as documented per endpoint.
Programmatic access (organization API keys, service accounts, future OAuth client credentials) is specified in PF-97: Multi-Tenant Organization API Access. Machine clients use a separate credential lifecycle (issue, rotate, revoke, scope) and MUST NOT rely on interactive user RBAC alone. Integration contracts and error shapes for machine clients will live in PF-97 integration once implementation is available.
Related: PF-30-EN-01 machine principals & scopes, PF-89-EN-01 machine client versioning.
Status Legend
- ✅ Implemented - Fully implemented and tested
- 📝 Planned - Specified but not yet implemented
- 🟡 In Progress - Partially implemented
Planned API Contracts
CL-68: Residential Episode Context (planned)
Provider: CL (CL-68) via@/platform/clinical platform layer (synchronous; SECURITY DEFINER RPC)
Consumers: PM-74 (authorization context), GR-27 (compliance counters)
Status: 📝 Planned
Spec Reference: CL-68 BHRF Clinical Residential Program; full contract CL-GR-PM-BHRF-EPISODE-LIFECYCLE
Purpose: Lets PM/GR read BHRF clinical-residential episode context without querying CL tables (no cross-core import). Returns coded context only — no clinical narrative. 42 CFR Part 2: locValue is redacted to null (not omitted) when CL-11 SUD consent is absent/revoked, and each access is audit-logged per §2.31; the function returns null only when the episode is inaccessible/not found. Consumers MUST treat locValue === null as “LOC not disclosable” (no fallback guessing). CL is architecturally downstream — consumers depend on this platform layer, not on CL-68.
Auth & Error Model
- Authentication: caller must present a valid bearer token (401 if unauthenticated).
- Tenant isolation: caller must be org-authorized for
organizationId(pf_has_org_accessor equivalent) validated before any lookup. Parameter scoping alone is not a boundary. Required permission scope:cl.bhrf.view(residential episode context read). - Error → return mapping (the two cross-tenant cases are distinct and unambiguous):
401— unauthenticated request.403— authenticated but not org-authorized for the suppliedorganizationId(cross-tenant/mismatched token, or missingcl.bhrf.view). Decided before any lookup.- top-level
null(404 semantics) — caller is org-authorized fororganizationId, but theepisodeIddoes not exist within that authorized tenant scope (existence is not revealed). Never used for an authorization failure. locValue === null— record exists but LOC redacted by 42 CFR Part 2 (CL-11 consent absent/revoked); the context object is still returned.- Operational failures return standardized platform errors — do not overload top-level
null.
- Audit: every access attempt is logged per §2.31, including whether
locValuewas redacted and any denied-access (401/403) outcome.
Synchronous API Contract
TypeScript Interface:GR-20: External LMS Bridge (planned)
Provider: GR-20 (External LMS Bridge) Consumers: GR-02 (training assignments), HR-22 / HR-27 (completion evidence) when implemented Status: 📝 Planned Spec Reference: GR-20 External LMS Bridge Purpose: Outbound REST/sync and optional inbound webhooks to external LMS vendors (SCORM/xAPI adapters). Contract payloads and auth live in the spec and futureGR-20-*-INTEGRATION.md; this row satisfies integration-contract coverage for GR-20 until the integration doc ships.
Synchronous API Contract
Endpoints:- Pull Completions:
GET /lms/completions?org_id={org_id}&since={date} - Push Enrollment:
POST /lms/enrollments
pushEnrollmentfailures: Event not acknowledged on failure; retried on next cron run- After 5 consecutive failures for the same enrollment,
gr_lms_sync_runs.statusmarked'failed'withrequires_attentionflag - Unmapped vendor users/courses: logged to
gr_lms_sync_runs.error_summary,records_failedincremented
- Relias
- HealthStream
- Cornerstone
- ADP Learning
- Workday Learning
- Pull operations: ≤10k completions per run, chunked per
gr_module_settings.lms.max_pull_batch_size - Target: <5 minutes per pull run (p95)
gr_lms_integrations: vendor configuration + vault secret referencegr_lms_user_mappings: vendor user ID ↔ hr_employees.idgr_lms_course_mappings: vendor course ID ↔ gr_training_courses.idgr_lms_sync_runs: audit trail of sync operations
UNMAPPED_USER: No mapping exists forexternal_user_idUNMAPPED_COURSE: No mapping exists forexternal_course_idVENDOR_AUTH_FAILED: Invalid credentialsVENDOR_RATE_LIMIT: Vendor rate limit exceededSYNC_RETRY_EXHAUSTED: 5+ consecutive failures
PF-43: Resource Quota Check (Database)
Provider: PF-43 (Tenant Resource Quotas)Consumers: Edge functions, server-side callers, client via
useResourceQuota hookStatus: 📝 Planned
Integration Doc: PF-43-tenant-resource-quotas-INTEGRATION.md Purpose: Server-side quota check before operations; client hook
useResourceQuota calls backend/edge that uses this function.
Database function: pf_check_resource_quota(organization_id, resource_type, requested_amount)Returns:
(allowed, remaining, reset_at, quota_id, limit_type) — reset_at is timestamptz (quota window reset); callers use it for countdown/display.
Request (logical):
organization_id(UUID): Tenant contextresource_type(TEXT): One ofstorage,api_calls,users,custom_objects,workflow_executionsrequested_amount(NUMERIC, optional): Amount to check; default 1
pf_resource_usage and pf_quota_violations via SECURITY DEFINER.
Client hook: useResourceQuota({ organizationId, resourceType, requestedAmount? }) — see spec API Design and integration doc.
PF-91: Compliance Edge Functions (internal)
Provider: PF-91 (Compliance Automation & Regulatory Dashboard)Consumers: Supabase cron, authenticated org admins (evidence only)
Status: 📝 Planned
Integration Doc: PF-91-compliance-automation-regulatory-dashboard-INTEGRATION.md Purpose: Internal Edge Function invocations (not public REST versioning). Contract shapes belong in the integration doc and
supabase/functions/*/README.md; this row tracks ownership.
| Function | Auth pattern | Request (logical) | Response (logical) |
|---|---|---|---|
compliance-run-checks | Service role / cron (verify_jwt documented false if cron-only) | Optional organization_id for single-tenant run | { runs_completed, checks_inserted } — no PHI payloads |
compliance-phi-scan | Service role / cron | Optional organization_id | { columns_scanned, rows_upserted, capped: boolean } |
generate-compliance-evidence | User JWT + pf.compliance.evidence.generate | organization_id, framework, date_range_start, date_range_end | { evidence_id, status } — client polls row + signed URL |
compliance-evidence with org-first path segment; signed URL download (see PF-91 integration doc).
Note: Final JSON Schemas — see PENDING_CONTRACTS.md until PF-91 implementation freezes payloads.
PF-96: Jurisdiction Profile Resolution RPC
Provider: PF-96 (Medicaid State Compliance Configuration) Consumers: All CL/PM features, PF-91 compliance dashboard, edge functions Status: 📝 Planned Integration Doc: PF-96-medicaid-state-compliance-configuration-INTEGRATION.md Spec Reference: PF-96 spec Purpose: Server-side jurisdiction profile resolution with four-tier merge (Federal Baseline → State Profile → Org Overrides → Site Overrides). Used by frontend hookuseJurisdictionProfile() and edge function helper getJurisdictionProfile().
Database RPC: pf_resolve_jurisdiction_profile(p_org_id UUID, p_site_id UUID DEFAULT NULL)
Type: PostgreSQL RPC (SECURITY DEFINER)
Resolution Order: Federal baseline → State profile (from pf_org_jurisdiction_config) → Org overrides → Site overrides (if p_site_id provided)
Parameters:
p_org_id(UUID, required): Organization IDp_site_id(UUID, optional): Site ID for site-level profile override
JSONB with the merged profile:
- Per-rule-pack JSONB merge (clinical, billing, compliance packs merged separately)
- Array fields replaced entirely (not appended) on override
- Federal baseline fields cannot be weakened (validated via
pf_validate_jurisdiction_override()trigger)
p_org_id (verified via pf_has_org_access()); if p_site_id is provided, the site must belong to the organization. Unauthorized calls return 403.
See also:
- PLATFORM_INTEGRATION_LAYERS.md#pf-96-jurisdiction-profile-integration-layer for hook usage
- EVENT_CONTRACTS.md#pf-96-jurisdiction-profile-changed for cache invalidation event
PF-101: Google Workspace Integration Edge Functions
Provider: PF-101 (Google Workspace Integration) Consumers: HR-01, CE-07, CE-21, PF-10, PF-11, PF-35, PF-86 Status: 🚧 Work in progress / partial delivery Integration Doc: PF-101-google-workspace-integration-INTEGRATION.md Spec Reference: PF-101 spec Purpose: Edge function contracts for Google Workspace Admin SDK Directory, Gmail, Calendar/Meet, Drive, Chat, Licensing, and Reports APIs. All functions use PF-76 credential retrieval, PF-42 rate limiting where applicable, sanitized errors, and correlation IDs.google-workspace-test-connection
Type: Edge Function (HTTP)
Auth: JWT + pf.google_workspace.test permission
Purpose: Validate capability scopes and health
Request:
MISSING_CONNECTION: Connection not foundINVALID_CREDENTIALS: Credentials invalid or expiredINSUFFICIENT_SCOPES: Required scopes not grantedBAA_NOT_ATTESTED: BAA attestation required for PHI-capable operations
google-workspace-directory-sync
Type: Edge Function (Service Role / Scheduled)
Auth: Service role (scheduled worker)
Purpose: Batch Directory user/group/org unit sync
Tenant-Scoping: REQUIRED - All queries MUST include .eq('organization_id', organizationId) and .eq('connection_id', connectionId) where applicable
Request:
google-workspace-provision-user
Type: Edge Function (Event Consumer + Service Role)
Auth: Service role (event consumer)
Purpose: Provision/link one Workspace user
Tenant-Scoping: REQUIRED - All queries MUST include .eq('organization_id', organizationId) and .eq('connection_id', connectionId) where applicable
Request:
google-workspace-offboard-user
Type: Edge Function (Event Consumer + Service Role)
Auth: Service role (event consumer)
Purpose: Suspend user, revoke licenses, remove groups, queue Drive review
Tenant-Scoping: REQUIRED - All queries MUST include .eq('organization_id', organizationId) and .eq('connection_id', connectionId) where applicable
Request:
google-workspace-gmail-send
Type: Edge Function (HTTP)
Auth: JWT + sender policy
Purpose: Shared Gmail sender path with sender allowlist, BAA gate, PF-86 signature, and redacted audit
Request:
SENDER_NOT_ALLOWED: Sender not in allowlistBAA_NOT_ATTESTED: BAA required for Gmail operationsQUOTA_EXCEEDED: Gmail send quota exceeded
google-workspace-calendar-sync
Type: Edge Function (JWT/Service Role)
Auth: JWT or service role
Purpose: Calendar/Meet event sync and CE wrapper support
Tenant-Scoping: REQUIRED - All queries MUST include .eq('organization_id', organizationId) and .eq('connection_id', connectionId) where applicable
Request:
google-workspace-drive-sync
Type: Edge Function (JWT/Service Role)
Auth: JWT or service role
Purpose: Drive metadata and mapping sync
Tenant-Scoping: REQUIRED - All queries MUST include .eq('organization_id', organizationId) and .eq('connection_id', connectionId) where applicable
Request:
google-workspace-reports-ingest
Type: Edge Function (Service Role / Scheduled)
Auth: Service role (scheduled worker)
Purpose: Reports API audit ingestion
Tenant-Scoping: REQUIRED - All queries MUST include .eq('organization_id', organizationId) and .eq('connection_id', connectionId) where applicable
Request:
google-workspace-chat-notify
Type: Edge Function (Service Role / PF-10)
Auth: Service role (PF-10 consumer)
Purpose: Send approved notifications to Chat spaces
Tenant-Scoping: REQUIRED - All queries MUST include .eq('organization_id', organizationId) and .eq('connection_id', connectionId) where applicable
Request:
Security & Compliance:
- No PHI-capable operations unless
pf_google_workspace_connections.baa_attested_atis set - All credentials stored in PF-76 only
- Domain-wide delegation scopes versioned and reviewed
- No PHI/PII in logs, cache keys, or telemetry
- PF-101-google-workspace-integration-INTEGRATION.md for detailed integration contracts
- EVENT_CONTRACTS.md for published events (
pf_google_workspace_user_provisioned,pf_google_workspace_connector_degraded)
PM-47: Managed Care Auth Tracking
Provider: PM-47 (Managed Care Authorization Tracking) Consumers: PM-08 (claims submission), PM dashboard, edge functions Status: 📝 Planned Integration Doc: PM-47-managed-care-authorization-tracking-INTEGRATION.md Spec Reference: PM-47 spec Purpose: Edge functions for auth expiration monitoring and pre-submission auth-to-claim validation.Edge Function: pm-auth-expiration-alerts
Type: Scheduled (Cron)
Method: Invoked by pg_cron daily at 6:00 AM
Auth: Service role (cron invocation)
Schedule: 0 6 * * *
Purpose: Check for authorizations reaching configured alert thresholds (14/7/3/1 days before expiration) and send PF-10 notifications to assigned UR coordinators.
Request: None (cron-triggered, no request body)
Response:
- Query
pm_managed_care_authorizationswhereexpiration_date - CURRENT_DATEmatches alert intervals frompm_module_settings.auth_alert_intervals_days - For each matching authorization, send notification via PF-10 with patient, payer, service type, expiration date, and remaining units
- Track sent alerts to avoid duplicates (idempotent)
Edge Function: pm-auth-claim-validation
Type: HTTP POST
Method: POST
Auth: JWT (user context)
Permission Required: pm.managed_care_auth.validate
Purpose: Validate claim lines against active authorizations before claim submission. Called by PM-08 claim submission workflow.
Request:
- For each claim line, query
pm_managed_care_authorizationswhere:organization_idmatchesstatus IN ('active', 'expiring')service_typematches claim line service typeeffective_date <= date_of_service <= expiration_date
- Check that
used_units + claim_line_units <= authorized_units - Return structured validation result per line
400 Bad Request→INVALID_REQUEST- Invalid input (missing fields, malformed data)403 Forbidden→ACCESS_DENIED- Auth/permission failure (missingpm.managed_care_auth.validatepermission or organization_id mismatch)404 Not Found→CLAIM_NOT_FOUND- Missing claim_id in request500 Internal Server Error→SERVER_ERROR- Server-side processing error
- Organization ID Validation: The incoming
organization_idin the request body MUST be validated against the authenticated JWT tenant context. Reject requests whereorganization_iddoes not match the JWT org claim. - Permission Check: Caller MUST have
pm.managed_care_auth.validatepermission for the organization. Return403 ACCESS_DENIEDif permission check fails. - Application-Layer Filtering: Implementations MUST apply
organization_idfiltering on all mutations (UPDATE/DELETE operations) to prevent cross-tenant access. - Database Layer: RLS policies and tenant-isolation MUST be enabled at the DB layer as defense-in-depth to prevent cross-tenant data access even if application-layer filtering fails.
CL-02-EN-60: Intake Element Completeness Checker RPC
Provider: CL (Clinical Core) Consumers: Internal use (triggers, application-layer completeness checks) Status: ✅ Complete Integration Doc: CL-02-EN-60-jurisdiction-aware-assessment-requirements-INTEGRATION.md Spec Reference: CL-02-EN-60 spec Purpose: Generic intake assessment element completeness checker that accepts a dynamic list of required elements from jurisdiction profiles, replacing Arizona-specific logic. Database RPC:cl_check_intake_elements(p_assessment_id UUID, p_required_elements JSONB)
Type: PostgreSQL RPC (SECURITY DEFINER)
Call Pattern: Synchronous
Parameters:
p_assessment_id(UUID, required): Intake assessment IDp_required_elements(JSONB, required): JSON array of required element codes (e.g.,'["presenting_problem","medical_history","sdoh_screening_completed"]')
JSONB with per-element boolean completion status:
cl_intake_assessments:
chief_complaint,presenting_problem→chief_complaint IS NOT NULL AND <> ''history_present_illness,history_of_present_illness→history_of_present_illness IS NOT NULL AND <> ''medical_history→medical_history IS NOT NULL AND <> ''mental_health_history,psychiatric_history→mental_health_history IS NOT NULL AND <> ''substance_use_history→substance_use_history IS NOT NULL AND <> ''social_history→social_history IS NOT NULL AND <> ''preliminary_diagnoses,diagnostic_formulation→preliminary_diagnoses IS NOT NULL AND jsonb_array_length(preliminary_diagnoses) > 0sdoh_screening_completed→sdoh_screening_id IS NOT NULL
- Returns
NULLif assessment not found - Returns empty object
{}ifp_required_elementsis empty array - Unknown element codes return
falsein result object
cl_check_ahcccs_18_elements(p_assessment_id UUID)— Legacy wrapper (DEPRECATED); callscl_check_intake_elementswith Arizona 18-element defaults
trg_cl_intake_element_completeoncl_intake_assessmentscalls this function to maintainintake_element_completecolumn
- PLATFORM_INTEGRATION_LAYERS.md#pf-96-jurisdiction-profile-integration-layer for profile-driven element lists
- EVENT_CONTRACTS.md for related event patterns
FA-01: Episode Balance Query
Endpoint:/api/v1/fa/episode-balance
Method: GET
Provider: FA (Finance & Accounting)
Consumer: RH (Recovery Housing) — episode detail page and bed board payment status
Status: 🟡 Partial — Edge function fa-episode-balance + hook useFaEpisodeBalance; FA AR ledger join 📋 Planned
Spec Reference:
- RH-01 Census, Beds & Episodes — Consumer specification
- RH-01.1 Bed Board & Facility Types — Bed board usage
- FA-01 (Chart of Accounts) — Provider foundation Integration Doc: RH-01-bed-board-census-INTEGRATION.md
episode_id(required): UUID of episodeas_of_date(optional): Date to calculate balance as of (ISO 8601 format, defaults to current date)
400 Bad Request: Invalid query parameters (e.g., malformed UUID, invalid date format)- Error code:
INVALID_DATEorINVALID_EPISODE_ID
- Error code:
401 Unauthorized: Missing or invalid JWT token- Error code:
UNAUTHORIZED
- Error code:
403 Forbidden: User does not have access to episode (RLS policy violation)- Error code:
ACCESS_DENIED
- Error code:
404 Not Found: Episode not found in FA system or episode belongs to different organization- Error code:
EPISODE_NOT_FOUND
- Error code:
429 Too Many Requests: Rate limit exceeded- Error code:
RATE_LIMIT_EXCEEDED - Response includes
X-RateLimit-Limit,X-RateLimit-Remaining,X-RateLimit-Resetheaders
- Error code:
500 Internal Server Error: Internal FA error- Error code:
SERVER_ERROR
- Error code:
- JWT required in
Authorization: Bearer {token}header - Token validated against Supabase Auth
- RLS policies enforce organization isolation
- User must have access to the episode’s organization
- 100 requests/minute per organization
- Rate limit headers included in all responses:
X-RateLimit-Limit: 100X-RateLimit-Remaining: Remaining requests in current windowX-RateLimit-Reset: Unix timestamp when limit resets
- Balance calculation includes all transactions up to
as_of_date - Past due balance calculated as transactions >30 days overdue
- Payment status determined by balance and payment history
- All amounts in organization’s base currency
- Response cached for 5 minutes (same episode_id + as_of_date)
Last Updated: 2026-03-20
FA-10: Tax Reporting APIs
Status: 📝 PlannedSpec Reference: FA-10 (Tax Reporting & Compliance)
Last Verified: N/A – planned
API 1: Generate 1099 Forms
Endpoint:/api/v1/fa/tax/1099/generateMethod: POST
Provider: FA (Finance & Accounting)
Consumer: Internal (FA module)
Status: 📝 Planned Tenant Context Enforcement:
- The
organization_idfrom the request body MUST be validated against the authenticated session’s organization membership usingpf_has_org_access(organization_id, auth.uid()) - If the request
organization_iddoes not match any organization the caller has access to, return403 ACCESS_DENIED - Do NOT trust
organization_idfrom the request body alone; always derive from authenticated session or validate via helper function
- ❌ NEVER log: Vendor names, vendor emails, tax identification numbers (EIN/SSN), bank account fragments, payment amounts in error logs
- ✅ ALLOWED in logs: UUIDs (form_id, vendor_id, tax_year_id), error codes, operation timestamps, organization_id
- Restrict
error.detailsto non-sensitive identifiers only (UUIDs, codes, timestamps)
FA-11: Fixed Assets APIs
Status: 📝 PlannedSpec Reference: FA-11 (Fixed Assets & Depreciation)
Last Verified: N/A – planned
API 1: Asset Depreciation
Endpoint:/api/v1/fa/assets/{asset_id}/depreciationMethod: GET
Provider: FA (Finance & Accounting)
Consumer: FA-07 (Financial Reporting)
Status: 📝 Planned (Implementation: client-side — Supabase queries from FA module) Tenant Context Enforcement:
- The asset’s
organization_idMUST be validated against the authenticated session usingpf_has_org_access(organization_id, auth.uid()) - Return
403 ACCESS_DENIEDif the asset belongs to an organization the caller cannot access
- ❌ NEVER log: Asset serial numbers, purchase prices, vendor details, location addresses in error logs
- ✅ ALLOWED in logs: UUIDs (asset_id, journal_entry_id), error codes, timestamps, organization_id
API 2: Process Monthly Depreciation
Endpoint:/api/v1/fa/assets/depreciation/processMethod: POST
Provider: FA (Finance & Accounting)
Consumer: Internal (FA module)
Status: 📝 Planned (Implementation: client-side — Supabase mutations from FA module) Tenant Context Enforcement:
- The
organization_idfrom the request body MUST be validated against the authenticated session usingpf_has_org_access(organization_id, auth.uid()) - Return
403 ACCESS_DENIEDif the organization is not accessible
- ❌ NEVER log: Asset serial numbers, purchase prices, vendor details, location addresses in error logs
- ✅ ALLOWED in logs: UUIDs (organization_id, asset_id), error codes, timestamps, counts
FA-12: Expense Management APIs
Status: 📝 PlannedSpec Reference: FA-12 (Expense Management & Reimbursements)
Last Verified: N/A – planned
API 1: Approve Expense Report
Endpoint:/api/v1/fa/expenses/reports/{report_id}/approveMethod: POST
Provider: FA (Finance & Accounting)
Consumer: FW-03 (Approval Workflow)
Status: 📝 Planned (Implementation: client-side — Supabase + workflow from FA/FW modules) Tenant Context Enforcement:
- The expense report’s
organization_idMUST be validated against the authenticated session usingpf_has_org_access(organization_id, auth.uid()) - Return
403 ACCESS_DENIEDif the report belongs to an organization the caller cannot access
- ❌ NEVER log: Employee names, receipt images, credit card numbers, bank account details, expense descriptions containing PHI
- ✅ ALLOWED in logs: UUIDs (report_id, employee_id), error codes, timestamps, organization_id, status codes
FA-13: Project Accounting APIs
Status: 📝 PlannedSpec Reference: FA-13 (Project Accounting & Grant Tracking)
Last Verified: N/A – planned
API 1: Project Budget vs Actual
Endpoint:/api/v1/fa/projects/{project_id}/budget-vs-actualMethod: GET
Provider: FA (Finance & Accounting)
Consumer: FA-07 (Financial Reporting), FA-08 (Budgeting)
Status: 📝 Planned (Implementation: client-side — Supabase/RPC from FA module) Tenant Context Enforcement:
- The project’s
organization_idMUST be validated against the authenticated session usingpf_has_org_access(organization_id, auth.uid()) - Return
403 ACCESS_DENIEDif the project belongs to an organization the caller cannot access
- ❌ NEVER log: Grant recipient names, client identifiers, project descriptions containing PHI
- ✅ ALLOWED in logs: UUIDs (project_id, account_id), error codes, timestamps, organization_id
period_start(optional): Start date for periodperiod_end(optional): End date for period
FA-14: Cash Management APIs
Status: 📝 PlannedSpec Reference: FA-14 (Cash Management & Treasury)
Last Verified: N/A – planned
API 1: Cash Position
Endpoint:/api/v1/fa/cash/positionMethod: GET
Provider: FA (Finance & Accounting)
Consumer: FA-07 (Financial Reporting), FA-16 (Analytics)
Status: 📝 Planned (Implementation: client-side — Supabase/hooks from FA module) Tenant Context Enforcement:
- The
organization_idMUST be derived from the authenticated session (not from query parameters) - If a request includes
organization_idin query params, validate it matches the caller’s accessible organizations viapf_has_org_access(organization_id, auth.uid()) - Return
403 ACCESS_DENIEDfor mismatches
- ❌ NEVER log: Bank account numbers, routing numbers, account holder names, transaction details
- ✅ ALLOWED in logs: UUIDs (organization_id), error codes, timestamps, aggregated amounts (without account-level detail)
as_of_date(optional): Date for cash position (defaults to current date)
API 2: Update Cash Position
Endpoint:/api/v1/fa/cash/positionMethod: PUT
Provider: FA (Finance & Accounting)
Consumer: Internal (FA module), FA-06 (Bank Reconciliation)
Status: 📝 Planned (Implementation: client-side — Supabase mutations from FA module) Tenant Context Enforcement:
- The
organization_idfrom the request body MUST be validated against the authenticated session usingpf_has_org_access(organization_id, auth.uid()) - Return
403 ACCESS_DENIEDif the organization is not accessible
- ❌ NEVER log: Bank account numbers, routing numbers, account holder names, transaction details
- ✅ ALLOWED in logs: UUIDs (organization_id, position_id), error codes, timestamps, aggregated amounts
API 3: Create Investment
Endpoint:/api/v1/fa/investmentsMethod: POST
Provider: FA (Finance & Accounting)
Consumer: Internal (FA module)
Status: 📝 Planned Tenant Context Enforcement:
- The
organization_idfrom the request body MUST be validated against the authenticated session usingpf_has_org_access(organization_id, auth.uid()) - Return
403 ACCESS_DENIEDif the organization is not accessible
- ❌ NEVER log: Investment account numbers, bank details, account holder names
- ✅ ALLOWED in logs: UUIDs (organization_id, investment_id), error codes, timestamps
FA-15: Cost Allocation APIs
Status: 📝 PlannedSpec Reference: FA-15 (Cost Allocation & Indirect Cost Rates)
Last Verified: N/A – planned
API 1: Allocate Indirect Costs
Endpoint:/api/v1/fa/idc/rates/{rate_id}/allocateMethod: POST
Provider: FA (Finance & Accounting)
Consumer: FA-13 (Project Accounting)
Status: 📝 Planned Tenant Context Enforcement:
- The rate’s
organization_idand all projectorganization_idvalues MUST be validated against the authenticated session usingpf_has_org_access(organization_id, auth.uid()) - Return
403 ACCESS_DENIEDif any referenced entity belongs to an inaccessible organization
- ❌ NEVER log: Project names containing client identifiers, grant recipient details
- ✅ ALLOWED in logs: UUIDs (rate_id, project_id, journal_entry_id), error codes, timestamps, organization_id
FA-16: Financial Analytics APIs
Status: 📝 PlannedSpec Reference: FA-16 (Financial Analytics & Dashboards)
Last Verified: N/A – planned
API 1: Financial Dashboard
Endpoint:/api/v1/fa/analytics/dashboardMethod: GET
Provider: FA (Finance & Accounting)
Consumer: Internal (FA module)
Status: 📝 Planned Tenant Context Enforcement:
- The
organization_idMUST be derived from the authenticated session (not from query parameters) - If a request includes
organization_idin query params, validate it matches the caller’s accessible organizations viapf_has_org_access(organization_id, auth.uid()) - Return
403 ACCESS_DENIEDfor mismatches
- ❌ NEVER log: Individual transaction details, vendor names, employee names, account-level breakdowns containing identifiers
- ✅ ALLOWED in logs: UUIDs (organization_id, kpi_id), error codes, timestamps, aggregated metrics only
period_start(optional): Start date for analyticsperiod_end(optional): End date for analytics
FA-17: Intercompany APIs
Status: 📝 PlannedSpec Reference: FA-17 (Intercompany Transactions)
Last Verified: N/A – planned
API 1: Generate Intercompany Eliminations
Endpoint:/api/v1/fa/intercompany/eliminations/generateMethod: POST
Provider: FA (Finance & Accounting)
Consumer: FA-09 (Consolidation)
Status: 📝 Planned Tenant Context Enforcement:
- The consolidation’s
organization_idand all related organization IDs MUST be validated against the authenticated session usingpf_has_org_access(organization_id, auth.uid()) - For intercompany transactions, validate access to both
source_org_idandtarget_org_id - Return
403 ACCESS_DENIEDif the caller lacks access to any involved organization
- ❌ NEVER log: Organization names, transaction descriptions containing identifiers
- ✅ ALLOWED in logs: UUIDs (consolidation_id, elimination_id, journal_entry_id), error codes, timestamps
FA-18: Revenue Recognition APIs
Status: 📝 PlannedSpec Reference: FA-18 (Revenue Recognition Advanced)
Integration: FA-18-revenue-recognition-advanced-INTEGRATION.md
Last Verified: 2026-04-26 — contract frozen (implementation pending migrations)
API 1: Recognize Revenue
Endpoint:/api/v1/fa/revenue/recognizeMethod: POST
Provider: FA (Finance & Accounting)
Consumer: Internal (FA module)
Status: 📝 Planned Implementation note: Primary server entry point is RPC
fa_process_revenue_recognition(organization_id, recognition_date, fiscal_period_id, user_id) per integration doc. This HTTP route, when implemented, is a thin wrapper that enforces PF-30 fa.revenue_recognitions.process and maps the body to RPC arguments.
Tenant Context Enforcement:
- All revenue schedules’
organization_idvalues MUST be validated against the authenticated session usingpf_has_org_access(organization_id, auth.uid())(or equivalent FA tenant helper) - Return
403 ACCESS_DENIEDif any schedule belongs to an inaccessible organization or the caller lacksfa.revenue_recognitions.process
- ❌ NEVER log: Contract details, client names, revenue source identifiers
- ✅ ALLOWED in logs: UUIDs (schedule_id, recognition_id, journal_entry_id), error codes, timestamps, organization_id
FA-19: Financial Close APIs
Status: 📝 PlannedSpec Reference: FA-19 (Financial Close Management)
Last Verified: N/A – planned
API 1: Approve Close Period
Endpoint:/api/v1/fa/close/periods/{period_id}/approveMethod: POST
Provider: FA (Finance & Accounting)
Consumer: Internal (FA module)
Status: 📝 Planned Tenant Context Enforcement:
- The close period’s
organization_idMUST be validated against the authenticated session usingpf_has_org_access(organization_id, auth.uid()) - Return
403 ACCESS_DENIEDif the period belongs to an inaccessible organization
- ❌ NEVER log: Approval notes containing sensitive details, financial summaries with identifiers
- ✅ ALLOWED in logs: UUIDs (period_id, approved_by), error codes, timestamps, organization_id, status codes
- Unit tests for balance calculation logic
- Integration tests for RLS enforcement
- E2E tests for full request/response cycle
- Rate limiting tests
- Error handling tests for all error codes
RH-01: Current Residence/Bed Query (CL Chart — Optional)
Endpoint:/api/v1/rh/current-residence
Method: GET
Provider: RH (Recovery Housing)
Consumer: CL (Clinical & EHR) — patient chart, read-only
Status: 📝 Planned (CL-01 chart enhancements — optional)
Spec Reference:
- RH-01.1 Bed Board & Facility Types
- CL-01 Patient Chart & Clinical Summary Integration Doc: RH-01-bed-board-census-INTEGRATION.md
patient_id(required): UUID of the patient (frompf_patient_identities)
- RLS enforces org-level isolation; patient_id must belong to the caller’s organization.
- CL must not import directly from
@/cores/rh/...; use this Platform Integration Layer endpoint.
application/json (response); no request body (GET).
Authentication & Permissions:
- Scheme: Bearer JWT (Supabase session token).
- Required role/scope:
rh.beds.view— callers without this permission receive403 Forbidden. - Spec refs: RH-01.1 Bed Board & Facility Types · CL-01 Patient Chart.
- Allowed to log: Non-identifying metadata only — request timestamps, response status (e.g. 200, 404, 403, 429),
residence_id(redacted or hashed),facility_type. - Forbidden: Any patient identifiers (
patient_id,pf_patient_identities, names, DOB), exactadmission_datebeyond date-only if considered PHI, and JWT or token contents. - Practice: Redact or use hashed IDs for any IDs in logs; never log raw JWT or patient identifiers.
- Example log line:
GET /api/v1/rh/current-residence 200 residence_id=<redacted> facility_type=recovery_housing ts=2026-02-22T12:00:00Z
- RLS policies on
rh_episodes,rh_beds, andrh_residencesenforceorganization_idownership. patient_id(frompf_patient_identities) must belong to the caller’s organization; requests for cross-org patients return404 Not Found(not403) to avoid leaking existence.
- Limit: 60 requests / minute per authenticated user.
- Response headers:
X-RateLimit-Limit: 60,X-RateLimit-Remaining: {n},X-RateLimit-Reset: {unix_ts}. - Exceeded:
429 Too Many RequestswithRetry-Afterheader.
| HTTP Status | error.code | Condition |
|---|---|---|
| 400 | INVALID_PATIENT_ID | patient_id is not a valid UUID |
| 403 | FORBIDDEN | Caller lacks rh.beds.view permission |
| 404 | PATIENT_NOT_FOUND | patient_id not found in caller’s org |
| 429 | RATE_LIMIT_EXCEEDED | Per-user rate limit reached |
| 500 | INTERNAL_ERROR | Unexpected server-side failure |
- p50: < 100 ms · p95: < 500 ms · p99: < 1 000 ms.
- Server-side query timeout: 5 000 ms; returns
504 Gateway Timeoutif exceeded. - This endpoint reads cached census data; no heavy aggregates are executed.
- Safe to retry: GET is idempotent; callers may retry on
429(afterRetry-After) and503/504. - No write semantics; no idempotency key required.
- Response is cacheable; recommended client
Cache-Control: max-age=30, stale-while-revalidate=60. - Server sets
Cache-Control: public, max-age=30on200responses. - Callers should use TanStack Query with
staleTime: 30_000andgcTime: 300_000.
PF-30: Permission Check API
Endpoint: Database functionpf_has_permission()Provider: PF (Platform Foundation)
Consumer: All Cores
Status: 🟡 In Progress (Phase 1 Complete)
Spec Reference: PF-30 Permissions System V2
Implementation Notes (Phase 1 Complete - 2025-12-11):Purpose: Check if a user has a specific module permission, integrating with PF-26 for three-tier permission checks. Function Signature:
- Database schema created:
pf_custom_roles,pf_module_permissions,pf_role_permissions,pf_user_role_assignments- RLS policies implemented with proper WITH CHECK clauses
- ~168 module permissions seeded across 7 modules + system
- Helper function
pf_get_user_permissions()available for permission lookup
p_user_id(required): UUID of the user to checkp_organization_id(required): UUID of the organization contextp_permission_key(required): Permission key in format{module}.{entity}.{action}p_site_id(optional): UUID of site for site-scoped permission checks
TRUE: User has the permissionFALSE: User does not have the permission
- Function is
SECURITY DEFINERto avoid RLS recursion - Always uses
SET search_path = publicfor security - Logs permission checks to audit log when enabled
- Returns
FALSEon any error (fail closed)
- p50 < 20ms, p95 < 50ms, p99 < 100ms
- Optimized with database indexes on role and permission tables
- Frontend caching reduces database load
Last Updated: 2025-12-11
HR-01: Employee Lookup
Endpoint:/api/v1/hr/employees/{employee_id}
Method: GET
Provider: HR (Workforce)
Consumer: RH (Recovery Housing); optional CL consumer for provider lookup — see PM-17 integration doc.
Status: 📝 Planned (RH-06 Implementation, Q2 2026)
Spec Reference: RH-06 (Compliance & Staff Operations)
Tenant isolation: organization_id enforced by RLS; JWT required. All queries scoped by authenticated session/claims.
Purpose: Lookup employee details for staff assignments in Recovery Housing
Request:
employee_id(required): UUID of employee
404 Not Found: Employee not found403 Forbidden: User does not have access to employee500 Internal Server Error: Internal HR error
Rate Limiting: 100 requests/minute per organization
Version: v1.0.0 (planned)
HR-01: Employee Search
Endpoint:/api/v1/hr/employees
Method: GET
Provider: HR (Workforce)
Consumer: RH (Recovery Housing); optional CL consumer for provider lookup — see PM-17 integration doc.
Status: 📝 Planned (RH-06 Implementation, Q2 2026)
Spec Reference: RH-06 (Compliance & Staff Operations)
Tenant isolation: organization_id enforced by RLS; JWT required. All queries scoped by authenticated session/claims.
Purpose: Search employees for staff assignments in Recovery Housing
Request:
department(optional): Filter by department namestatus(optional): Filter by employment status (active, inactive, terminated)job_title(optional): Filter by job titlepage(optional): Page number (default: 1)page_size(optional): Results per page (default: 50, max: 100)
400 Bad Request: Invalid query parameters403 Forbidden: User does not have access500 Internal Server Error: Internal HR error
Rate Limiting: 100 requests/minute per organization
Version: v1.0.0 (planned)
HR-06 ↔ HR-11: Benefits-Enabled Leave Integration
Integration Type: API Contract (Pattern 3)Status: 📝 Planned (HR-06 Phase 2)
Version: 1.0
Provider: HR-11 (Benefits Administration)
Consumer: HR-06 Phase 2 (Leave Management) Purpose: Link leave policies to benefit plans and track benefits-eligible leave. Enables HR-06 to check employee benefit enrollment status and subscribe to enrollment changes. API Endpoints:
Query: Employee Benefit Enrollment Status
Hook:useEmployeeBenefitEnrollment(employeeId, planType)Location:
src/cores/hr/hooks/useEmployeeBenefitEnrollment.tsProvider: HR-11 Parameters:
employeeId(required): UUID of employeeplanType(required): Benefit plan type -'std' | 'ltd' | 'disability' | 'health' | 'dental' | 'vision' | 'retirement' | 'life'
Query: Leave Policy Benefits
Hook:useLeavePolicyBenefits(leavePolicyId)Location:
src/cores/hr/hooks/useLeavePolicyBenefits.tsProvider: HR-06 Phase 2 Parameters:
leavePolicyId(required): UUID of leave policy
- HR Admin links leave policy to benefit plan (creates
hr_leave_policy_benefitsrecord with FK tohr_benefits_plans) - Employee enrolls in benefit (HR-11 creates
hr_benefits_enrollmentsrecord) - HR-11 publishes
benefits_enrollment_approvedevent - HR-06 Phase 2 subscribes to event, updates leave eligibility
- Employee views leave request form, sees benefits-eligible status via
useEmployeeBenefitEnrollmenthook
benefits_enrollment_approved- HR-11 → HR-06 (enrollment status change to ‘approved’ or ‘active’)benefits_enrollment_terminated- HR-11 → HR-06 (enrollment termination)
- Event Contracts - Complete event schema
- HR-06 Phase 2-3 Expansion - Consumer specification
- HR-11 Benefits Administration - Provider specification
Last Updated: 2026-01-09
FW-19: Workflow Query Action
Endpoint: Edge functionworkflow-query-actionMethod: POST
Provider: FW (Forms & Workflow)
Consumer: Automation Executor
Status: 📝 Planned (FW-19 Implementation)
Spec Reference: FW-19 Data Query & Integration Actions Purpose: Execute parameterized queries against whitelisted database tables within workflow execution. Request:
400 Bad Request: Invalid query parameters or filters403 Forbidden: Table not in organization’s whitelist408 Request Timeout: Query exceeded 30s timeout500 Internal Server Error: Database error
Rate Limiting: 100 requests/minute per organization
Version: v1.0.0 (planned)
FW-19: Workflow API Action
Endpoint: Edge functionworkflow-api-actionMethod: POST
Provider: FW (Forms & Workflow)
Consumer: Automation Executor
Status: 📝 Planned (FW-19 Implementation)
Spec Reference: FW-19 Data Query & Integration Actions Purpose: Execute external API calls with authentication and retry logic within workflow execution. Request:
400 Bad Request: Invalid config or URL401 Unauthorized: External API authentication failed408 Request Timeout: External API exceeded timeout502 Bad Gateway: External API returned error after all retries500 Internal Server Error: Internal function error
Rate Limiting: 50 requests/minute per organization (lower due to external API calls)
Version: v1.0.0 (planned)
FW-22: Workflow Debug Control
Endpoint: Edge functionworkflow-debug-controlMethod: POST
Provider: FW (Forms & Workflow)
Consumer: Workflow Developer, Operations Engineer
Status: ✅ Implemented (FW-22 Phase 4)
Spec Reference: FW-22 Workflow Execution Monitoring & Debugging Purpose: Control debug sessions for workflow executions - start, pause, resume, step through. Request:
400 Bad Request: Invalid action or missing required fields403 Forbidden: User lacks debug permissions for this execution404 Not Found: Execution or session not found409 Conflict: Another user has an active debug session500 Internal Server Error: Debug control error
Rate Limiting: 100 requests/minute per organization
Version: v1.0.0 (released 2025-12-08)
FW-24: Sandbox Execute
Endpoint: Edge functionsandbox-executeMethod: POST
Provider: FW (Forms & Workflow)
Consumer: Workflow Developer, QA Engineer
Status: 📝 Planned (FW-24 Implementation)
Spec Reference: FW-24 Workflow Testing & Sandbox Purpose: Execute workflow in an isolated sandbox environment for testing. Request:
400 Bad Request: Invalid input data or rule_id403 Forbidden: User lacks workflow edit permissions404 Not Found: Rule or test dataset not found500 Internal Server Error: Sandbox execution error
Rate Limiting: 50 requests/minute per organization
Version: v1.0.0 (planned)
FW-24: Test Datasets Import
Endpoint: Edge functiontest-datasets-importMethod: POST
Provider: FW (Forms & Workflow)
Consumer: Workflow Developer, QA Engineer
Status: 📝 Planned (FW-24 Implementation)
Spec Reference: FW-24 Workflow Testing & Sandbox Purpose: Import test data from CSV or JSON files. Request:
file: File (CSV or JSON, max 10MB)organization_id: UUIDname: stringdescription: string (optional)
400 Bad Request: Invalid file format413 Payload Too Large: File exceeds 10MB limit422 Unprocessable Entity: Data validation errors
Rate Limiting: 10 requests/minute per organization
Version: v1.0.0 (planned)
FW-24: Test Cases Run
Endpoint: Edge functiontest-cases-runMethod: POST
Provider: FW (Forms & Workflow)
Consumer: Workflow Developer, QA Engineer
Status: 📝 Planned (FW-24 Implementation)
Spec Reference: FW-24 Workflow Testing & Sandbox Purpose: Execute test cases against a workflow in sandbox. Request:
400 Bad Request: Invalid test case IDs403 Forbidden: User lacks workflow edit permissions404 Not Found: Rule or test cases not found500 Internal Server Error: Test execution error
Rate Limiting: 20 requests/minute per organization
Version: v1.0.0 (planned) Usage Example:
FW-45: Evaluate Decision Table
Endpoint: Edge functionevaluate-decision-tableMethod: POST
Provider: FW (Forms & Workflow)
Consumer: Workflow steps, server-side validation, integrations
Status: ✅ Implemented
Spec Reference: FW-45 Decision Tables
Integration: Server-side evaluation +
fw_log_decision_table_evaluation RPC
Request body (logical): table_id, facts (record), optional version_id, evaluation_context (workflow_step | form_validation | api_request), optional source_execution_id, source_step_id.
Response (200): success, matched, matchedRuleCount, outputs, evaluationId, versionNumber, hitPolicy, optional error.
Authentication: JWT; org access verified per _shared/auth.ts.
FW-46: Workflow Executor Worker
Endpoint: Edge functionworkflow-executor-workerMethod: POST (typically invoked by pg_cron via
pg_net, not direct client)Provider: FW
Consumer: Platform scheduler / automation infrastructure
Status: ✅ Implemented
Spec Reference: FW-46 Durable Execution Worker Purpose: Dequeue from pgmq
workflow_execution_queue (primary) or claim queued rows (fallback); advance workflow execution with checkpoint integration (FW-48); route permanent failures toward DLQ (FW-47).
Request Body: Typically empty (cron invocation). Optional JSON body for manual testing:
200 OK- Success (may include partial failures inresults)400 Bad Request- Invalid request body500 Internal Server Error- Runtime error (e.g., queue read failure, semaphore acquisition failure)
- Updates
fw_module_settings.worker_runningandworker_last_run_at(semaphore pattern) - Updates
fw_module_settings.worker_last_batch_sizewith processed count - Routes failed executions to
workflow_dlq(FW-47) after max retries - Writes checkpoint data via FW-48 integration
- Emits domain events for execution state changes (if configured)
FW-49: Workflow Timeout Checker
Endpoint: Edge functionworkflow-timeout-checkerMethod: POST
Provider: FW
Consumer: pg_cron–scheduled watchdog
Status: ✅ Implemented
Spec Reference: FW-49 Execution Timeout & Watchdog
Integration: FW-49-execution-timeout-watchdog-INTEGRATION.md Purpose: Scan overdue executions, apply
on_timeout action (from timeout_config), emit workflow.execution.timed_out, integrate with FW-47 and PF-10.
Request Body: Empty (cron invocation via createCronHandler). Optional JSON for manual testing:
- Errors are logged but do not cause HTTP error responses (cron handler pattern)
- Individual execution processing errors increment
errorsCountand continue processing - Database query errors are logged with correlation ID
200 OK- Processing completed (may includeerrorsCount > 0)
- Updates
fw_workflow_executions.statusto'timed_out'or'cancelled'based ontimeout_config.on_timeout - Sets
fw_workflow_executions.completed_atanderror_messagefor timed-out executions - Sends notifications via PF-10 (
createNotificationIfNew) for:- Timeout events (normal or high priority for escalate)
- At-risk warnings (when
elapsedPercent >= warning_threshold_percent)
- Updates
fw_workflow_executions.timeout_warning_sent = trueafter warning sent - Emits
workflow.execution.timed_outdomain event (if configured)
FW-49: Extend Execution Deadline
Endpoint: Edge functionextend-execution-deadlineMethod: POST
Provider: FW
Consumer: FW UI (admin), execution detail
Status: ✅ Implemented
Spec Reference: FW-49 Execution Timeout & Watchdog Request Body:
200 OK- Deadline extended successfully400 Bad Request- Validation error:- Missing required fields (
execution_id,organization_id,extension_minutes,reason) extension_minutesoutside valid range (1-1440)reasonlength invalid (5-500 characters)- Execution status not active (
running,paused,pending,queued)
- Missing required fields (
401 Unauthorized- Missing or invalid JWT token403 Forbidden- Insufficient permissions (workflow admin required)404 Not Found- Execution not found ororganization_idmismatch500 Internal Server Error- Database update failure
- Updates
fw_workflow_executions.deadline_atwith new deadline - Resets
fw_workflow_executions.timeout_warning_sent = falseto allow new warnings - Logs audit event with correlation ID, user ID, extension details, and timestamps
validateAuth() from _shared/auth.ts. Requires fw.workflows.admin permission or equivalent org admin role.
FW-52: Workflow Export (Edge Function)
Endpoint: Edge functionfw-workflow-exportMethod: POST
Provider: FW
Consumer: FW UI,
fw-promote CLIStatus: 📝 Planned
Spec Reference: FW-52 Workflow Import/Export & Portability
Integration Doc: FW-52-workflow-import-export-portability-INTEGRATION.md Request Body (logical):
WorkflowExportPackage JSON (see spec schema).
Authentication: JWT; verifyOrgAccess; permission fw.workflows.export.
FW-52: Workflow Import (Edge Function)
Endpoint: Edge functionfw-workflow-importMethod: POST
Provider: FW
Consumer: FW UI,
fw-promote CLIStatus: 📝 Planned
Spec Reference: FW-52 Workflow Import/Export & Portability
Integration Doc: FW-52-workflow-import-export-portability-INTEGRATION.md Request Body (logical):
{ success: true, import_log_id: string }.
Authentication: JWT; verifyOrgAccess; permission fw.workflows.import.
API Implementation Guidelines
Authentication
All API endpoints MUST:- Require JWT authentication in Authorization header
- Validate JWT token and extract user context
- Enforce RLS policies based on user’s organization access
- Return
401 Unauthorizedfor missing/invalid tokens - Return
403 Forbiddenfor insufficient permissions
Rate Limiting
All API endpoints MUST:- Implement per-organization rate limits
- Default limit: 100 requests/minute per organization
- Return
429 Too Many Requestswhen limit exceeded - Include rate limit headers in response:
X-RateLimit-Limit: Maximum requests per windowX-RateLimit-Remaining: Remaining requests in windowX-RateLimit-Reset: Time when limit resets
Error Handling
All API endpoints MUST:- Use standard HTTP status codes
- Return consistent error response format:
- Log all errors for debugging
- Never expose sensitive data in error messages
Response Format
All successful responses MUST:- Return JSON with consistent structure
- Include metadata when applicable (pagination, timestamps)
- Use camelCase for field names
- Include
organization_idfor multi-tenant context
Planned API Contracts (IT Module)
The IT (Information Technology) module defines 4 planned API contracts for asset, vendor, and license management. Full IT API documentation: IT Integration ContractsIT-01: Asset Lookup
Endpoint:/api/v1/it/assets/{asset_id}Method: GET
Provider: IT (IT-01 Asset Management)
Consumer: IT-02 (Support Ticketing), IT-05 (Security)
Status: 📝 Planned
Spec Reference: IT-01 IT Asset Management Purpose: Lookup IT asset details for ticket linking and security tracking. Response Schema (200 OK):
404 Not Found, 403 Forbidden, 500 Internal Server ErrorAuthentication: JWT required, RLS enforces organization isolation
Rate Limiting: 100 requests/minute per organization
IT-01: Asset Search
Endpoint:/api/v1/it/assetsMethod: GET
Provider: IT (IT-01 Asset Management)
Consumer: IT-02, IT-04, IT-05, IT-06
Status: 📝 Planned Query Parameters:
asset_type(optional): Filter by asset typestatus(optional): Filter by statussite_id(optional): Filter by sitesearch(optional): Search by asset tag, name, or serial numberpage,page_size: Pagination
Rate Limiting: 100 requests/minute per organization
IT-03: Vendor Lookup
Endpoint:/api/v1/it/vendors/{vendor_id}Method: GET
Provider: IT (IT-03 Vendor Management)
Consumer: IT-01, IT-04, IT-06
Status: 📝 Planned
Spec Reference: IT-03 IT Vendor Management Purpose: Lookup IT vendor details for asset, license, and procurement linking. Response Schema (200 OK):
Rate Limiting: 100 requests/minute per organization
IT-04: License Compliance Check
Endpoint: Database functionit_check_license_compliance()Provider: IT (IT-04 Software License Management)
Consumer: IT-04 Dashboard, scheduled compliance checks
Status: 📝 Planned
Spec Reference: IT-04 Software License Management Purpose: Check license compliance for a software license or all licenses. Function Signature:
SECURITY DEFINER with SET search_path = public
FA-19: Financial Close Management APIs
Status: ✅ ImplementedSpec Reference: FA-19-financial-close-management.md
Last Verified: 2026-01-19
API 1: Close Period Approval
Endpoint:/api/v1/fa/close/periods/{period_id}/approveMethod: POST
Provider: FA (Finance & Accounting)
Consumer: FW-03 (Approval Workflow), FA-19 Internal
Status: ✅ Implemented Purpose: Approve or reject a close period after all tasks are complete. This is a critical control point in the financial close process. Tenant Context Enforcement:
- The close period’s
organization_idMUST be validated against the authenticated session usingpf_has_org_access(organization_id, auth.uid()) - Return
403 ACCESS_DENIEDif the period belongs to an organization the caller cannot access - User must have
fa.close.approvepermission
- ❌ NEVER log: User names, comments containing PII, financial amounts
- ✅ ALLOWED in logs: UUIDs (period_id, user_id), error codes, timestamps, organization_id, status codes
400 Bad Request: Invalid request body403 Forbidden: User lacksfa.close.approvepermission or organization access- Error code:
ACCESS_DENIEDorPERMISSION_DENIED
- Error code:
404 Not Found: Close period not found- Error code:
PERIOD_NOT_FOUND
- Error code:
409 Conflict: Period not inpending_approvalstatus or has incomplete tasks- Error code:
INVALID_STATUSorINCOMPLETE_TASKS
- Error code:
500 Internal Server Error: Unexpected error- Error code:
SERVER_ERROR
- Error code:
- Period must be in
pending_approvalstatus - All tasks must be
completedorskippedbefore approval - Approval triggers
close_period_approvedevent - Rejection triggers status change back to
in_progress - Approval locks period from further modifications
API 2: Close Period Status Query
Endpoint:/api/v1/fa/close/periods/{period_id}/statusMethod: GET
Provider: FA (Finance & Accounting)
Consumer: FA-07 (Financial Reporting), FA-02 (General Ledger)
Status: ✅ Implemented Purpose: Query the current status and progress of a close period. Used by Financial Reporting to verify close status before generating final reports. Tenant Context Enforcement:
- The close period’s
organization_idMUST be validated against the authenticated session usingpf_has_org_access(organization_id, auth.uid()) - Return
403 ACCESS_DENIEDif the period belongs to an organization the caller cannot access
- ❌ NEVER log: User names, task descriptions containing PHI
- ✅ ALLOWED in logs: UUIDs (period_id), error codes, timestamps, organization_id, task counts
403 Forbidden: User does not have access to period’s organization- Error code:
ACCESS_DENIED
- Error code:
404 Not Found: Close period not found- Error code:
PERIOD_NOT_FOUND
- Error code:
- Used by FA-07 to verify period is closed before final reporting
- Completion percentage = (completed + skipped) / total * 100
- Task summary aggregated from fa_close_tasks
- Returns fiscal_period_id if close period is linked to fiscal period
FA-19 Consumed APIs
From FA-02 (General Ledger):fa_fiscal_periodstable query for linking close periods to fiscal periods- Period status validation before close approval
- Fiscal period closed status check
- Close status check before generating final reports
fa_report_definitionsquery for close-related reports
PF-59: AI Edge Functions (OpenRouter)
Status: 🔄 Updated (PF-59 migration from Lovable AI Gateway)Implemented: 2025-12-06 (PF-27), Updated 2026-01-28 (PF-59)
Spec Reference:
- PF-27-platform-ai.md - Original specification
- PF-59-ai-provider-migration.md - OpenRouter migration
ai-assistant
Endpoint:/functions/v1/ai-assistantMethod: POST
Provider: PF (Platform Foundation)
Consumer: All cores via
@/platform/ai hooksStatus: ✅ Implemented (PF-27), 🔄 Updated (PF-59) Purpose: Streaming AI chat with module-specific system prompts and automatic model selection based on module context. Request Schema:
- Server-Sent Events (SSE) stream with chunks:
- Automatically selected based on
moduleContext.module:gr,hr→anthropic/claude-3.5-sonnetfa,fw,rh,pf→openai/gpt-4olo,fm→openai/gpt-4o-mini- Unknown/default →
openai/gpt-4o
400 Bad Request: Invalid request format or PHI detected- Error code:
INVALID_REQUESTorPHI_DETECTED
- Error code:
401 Unauthorized: Missing or invalid JWT token- Error code:
UNAUTHORIZED
- Error code:
402 Payment Required: AI credits depleted- Error code:
CREDITS_DEPLETED - User message: “AI credits depleted”
- Error code:
429 Too Many Requests: Rate limited- Error code:
RATE_LIMITED - User message: “Rate limited, please try again”
- Automatic exponential backoff retry (max 3 retries)
- Error code:
500 Internal Server Error: OpenRouter service error- Error code:
SERVICE_ERROR - User message: “AI service error. Please try again.”
- Error code:
- JWT required in
Authorization: Bearer {token}header - Token validated against Supabase Auth
- Organization ID derived from authenticated user profile
- The
organization_idis derived from the authenticated user viaauth.uid()and user profile metadata - If
moduleContext.organization_idis provided, it MUST be validated usingpf_has_org_access(organization_id, auth.uid()) - If validation fails (user does not have access to the specified organization), return
403 Forbiddenwith error codeACCESS_DENIED - Never trust client-provided organization IDs without validation
- FORBIDDEN: Do NOT log user messages, AI responses, conversation history, or moduleContext identifiers
- ALLOWED: Log UUIDs (correlation_id, user_id), error codes, timestamps, organization_id (UUID only), model selection, and aggregated token counts
- Usage logging to
pf_ai_usage_logsand telemetry MUST exclude message content and AI responses - Only log metadata required for billing, debugging, and analytics (token counts, model used, success/failure status)
- OpenRouter enforces rate limits
- Exponential backoff: 1s initial, max 30s delay, max 3 retries
- Retry only on 429 errors
OPENROUTER_API_KEY(required) - OpenRouter API keyAPP_URL(optional) - Application URL for referrer header (defaults to https://encoreos.io)
- Streaming responses use Server-Sent Events (SSE)
- PHI detection runs on user messages before sending to AI
- Module context enables specialized system prompts
- Usage logged to
pf_ai_usage_logstable (metadata only, no content)
- Streaming:
text/event-stream; charset=utf-8 - Non-streaming:
application/json
- p50 latency: <500ms (time-to-first-token for streaming)
- p95 latency: <2s (time-to-first-token for streaming)
- p99 latency: <5s (time-to-first-token for streaming)
- Non-streaming response: <3s p95
- Default timeout: 30s (configurable via
OPENROUTER_TIMEOUTenvironment variable) - Streaming timeout: 60s (longer for streaming responses)
- Client should set appropriate timeout based on expected response length
- Non-idempotent: Identical requests may produce different responses due to:
- Model non-determinism (temperature > 0)
- Context window state differences
- Rate limiting and retry behavior
- Clients should not retry identical requests expecting identical results
- Use
correlationIdfor tracking related requests
- Non-retryable errors (do not retry):
400 Bad Request(INVALID_REQUEST, PHI_DETECTED) - Client error, retry won’t help401 Unauthorized- Authentication issue, retry won’t help402 Payment Required(CREDITS_DEPLETED) - Billing issue, retry won’t help403 Forbidden(ACCESS_DENIED) - Permission issue, retry won’t help
- Retry on 429 (Rate Limited):
- Exponential backoff: 1s initial delay, max 30s delay, max 3 retries
- Retry-After header should be respected if present
- Client should implement jitter to avoid thundering herd
- Client guidance for 500 (Internal Server Error):
- Retry with exponential backoff (1s, 2s, 4s delays)
- Max 3 retries for 500 errors
- If all retries fail, show user-friendly error message
- Log correlationId for support
- No caching: Responses are not cached
- No TTL: Each request is processed fresh
- Clients may cache responses locally if needed, but server does not cache
- Unit Tests:
- Model selection logic based on
moduleContext.module - PHI detection function (positive and negative cases)
- Error handling for all error codes (400, 401, 402, 403, 429, 500)
- Request validation (message format, required fields)
- Model selection logic based on
- Integration/E2E Tests:
- Streaming behavior (SSE format validation, chunk parsing)
- Non-streaming response format
- Authentication flow (JWT validation)
- Rate limiting behavior (429 responses)
- Timeout handling
- Tenant Isolation/RLS Tests:
- Exercise
pf_has_org_access()function for organization_id validation - Verify cross-tenant access is denied (403 Forbidden)
- Test with users from different organizations
- Verify RLS policies prevent data leakage
- Exercise
Last Updated: 2026-01-28
ai-document-analyze
Endpoint:/functions/v1/ai-document-analyzeMethod: POST
Provider: PF (Platform Foundation)
Consumer: All cores via
@/platform/ai hooksStatus: ✅ Implemented (PF-27), 🔄 Updated (PF-59) Purpose: Analyze documents using AI with structured JSON output. Optimized for document extraction and analysis tasks. Request Schema:
openai/gpt-4o (optimized for structured output)
Error Codes:
- Same as
ai-assistant(400, 401, 402, 429, 500) 403 Forbidden: Access denied when document’s organization_id validation fails- Error code:
ACCESS_DENIED - User message: “Access denied to this document”
- Error code:
ai-assistant (JWT required)
Tenant Context Enforcement:
- The document’s
organization_id(frompf_documentstable) MUST be validated usingpf_has_org_access(document.organization_id, auth.uid()) - If validation fails, return
403 Forbiddenwith error codeACCESS_DENIED - Never process documents from organizations the user cannot access
- FORBIDDEN: Do NOT log document content, analysis results containing PHI/PII, or schema outputs with sensitive fields
- ALLOWED: Log UUIDs (document_id, correlation_id), error codes, timestamps, confidence scores (without content), and non-sensitive metadata
- Analysis results and extracted fields may contain PHI/PII and MUST NOT be logged to application logs, telemetry, or audit trails
- Only log metadata required for debugging and analytics (document_id, success/failure, processing time, model used)
ai-assistant
Content-Type Headers:
application/json(non-streaming only)
- p50 latency: <2s
- p95 latency: <5s
- p99 latency: <10s
- Default timeout: 30s (configurable via
OPENROUTER_TIMEOUTenvironment variable) - Client should set appropriate timeout based on document size
- Non-idempotent: Identical requests may produce different analysis results due to:
- Model non-determinism (temperature > 0)
- Document content changes (if document is updated between requests)
- Clients should not retry identical requests expecting identical results
- Use
correlationIdfor tracking related requests
- Non-retryable errors (do not retry):
400 Bad Request(INVALID_REQUEST, PHI_DETECTED) - Client error, retry won’t help401 Unauthorized- Authentication issue, retry won’t help402 Payment Required(CREDITS_DEPLETED) - Billing issue, retry won’t help403 Forbidden(ACCESS_DENIED) - Permission issue, retry won’t help
- Retry on 429 (Rate Limited):
- Exponential backoff: 1s initial delay, max 30s delay, max 3 retries
- Retry-After header should be respected if present
- Client should implement jitter to avoid thundering herd
- Client guidance for 500 (Internal Server Error):
- Retry with exponential backoff (1s, 2s, 4s delays)
- Max 3 retries for 500 errors
- If all retries fail, show user-friendly error message
- Log correlationId for support
- No caching: Responses are not cached
- No TTL: Each request is processed fresh
- Clients may cache analysis results locally if needed, but server does not cache
- Unit Tests:
- Model selection (should use
openai/gpt-4ofor structured output) - PHI detection function (positive and negative cases)
- Error handling for all error codes (400, 401, 402, 403, 429, 500)
- Request validation (documentId format, schema validation)
- Model selection (should use
- Integration/E2E Tests:
- Response format validation (analysis, confidence, extractedFields)
- Authentication flow (JWT validation)
- Rate limiting behavior (429 responses)
- Timeout handling
- Tenant Isolation/RLS Tests:
- Exercise
pf_has_org_access()function for document organization_id validation - Verify cross-tenant access is denied (403 Forbidden)
- Test with users from different organizations accessing same document
- Verify RLS policies prevent data leakage
- Exercise
Last Updated: 2026-01-28
generate-report-narrative
Endpoint:/functions/v1/generate-report-narrativeMethod: POST
Provider: PF (Platform Foundation)
Consumer: All cores via
@/platform/ai hooksStatus: ✅ Implemented (PF-27), 🔄 Updated (PF-59) Purpose: Generate narrative text for reports based on data and context. Optimized for narrative generation tasks. Request Schema:
openai/gpt-4o (optimized for narrative generation)
Error Codes:
- Same as
ai-assistant(400, 401, 402, 429, 500) 403 Forbidden: Access denied when report’s organization_id validation fails- Error code:
ACCESS_DENIED - User message: “Access denied to this report”
- Error code:
ai-assistant (JWT required)
Tenant Context Enforcement:
- The incoming
request.reportDataMUST includeorganization_id - The server MUST validate access using
pf_has_org_access(reportData.organization_id, auth.uid()) - If validation fails (user does not have access to the specified organization), return
403 Forbiddenwith error codeACCESS_DENIED - Never generate narratives for reports from organizations the user cannot access
- FORBIDDEN: Do NOT log report content, generated narrative text, or summaries containing identifiers or financial data
- ALLOWED: Log UUIDs (report_id, correlation_id), error codes, timestamps, and non-content metadata (reportType as enum, not content)
- Report data, narratives, and summaries may contain PHI/PII and financial information and MUST NOT be logged to application logs, telemetry, or audit trails
- Only log metadata required for debugging and analytics (report_id, reportType enum, success/failure, processing time, model used)
ai-assistant
Content-Type Headers:
application/json(non-streaming only)
- p50 latency: <3s
- p95 latency: <8s
- p99 latency: <15s
- Default timeout: 30s (configurable via
OPENROUTER_TIMEOUTenvironment variable) - Client should set appropriate timeout based on report data size
- Non-idempotent: Identical requests may produce different narrative text due to:
- Model non-determinism (temperature > 0)
- Report data changes (if report is updated between requests)
- Clients should not retry identical requests expecting identical results
- Use
correlationIdfor tracking related requests
- Non-retryable errors (do not retry):
400 Bad Request(INVALID_REQUEST, PHI_DETECTED) - Client error, retry won’t help401 Unauthorized- Authentication issue, retry won’t help402 Payment Required(CREDITS_DEPLETED) - Billing issue, retry won’t help403 Forbidden(ACCESS_DENIED) - Permission issue, retry won’t help
- Retry on 429 (Rate Limited):
- Exponential backoff: 1s initial delay, max 30s delay, max 3 retries
- Retry-After header should be respected if present
- Client should implement jitter to avoid thundering herd
- Client guidance for 500 (Internal Server Error):
- Retry with exponential backoff (1s, 2s, 4s delays)
- Max 3 retries for 500 errors
- If all retries fail, show user-friendly error message
- Log correlationId for support
- No caching: Responses are not cached
- No TTL: Each request is processed fresh
- Clients may cache narrative text locally if needed, but server does not cache
- Unit Tests:
- Model selection (should use
openai/gpt-4ofor narrative generation) - PHI detection function (positive and negative cases)
- Error handling for all error codes (400, 401, 402, 403, 429, 500)
- Request validation (reportData format, context validation)
- Model selection (should use
- Integration/E2E Tests:
- Response format validation (narrative, summary)
- Authentication flow (JWT validation)
- Rate limiting behavior (429 responses)
- Timeout handling
- Tenant Isolation/RLS Tests:
- Exercise
pf_has_org_access()function for reportData organization_id validation - Verify cross-tenant access is denied (403 Forbidden)
- Test with users from different organizations accessing same report
- Verify RLS policies prevent data leakage
- Exercise
Last Updated: 2026-01-28
PF-65: Gusto Embedded Payroll Proxy
Endpoint:POST /functions/v1/gusto-proxyStatus: ✅ Implemented
Auth: Bearer JWT (Supabase session)
Provider: PF (Platform Foundation)
Consumer: HR core, Gusto Embedded SDK components
Purpose
Forward Gusto Embedded SDK requests to https://api.gusto.com with server-injected OAuth token andx-gusto-client-ip header. No Gusto credentials exposed to frontend.
Request Schema
Response
- Success: Same status and body as Gusto API response
- 401 Unauthorized: Missing or invalid JWT
- 403 Forbidden: Organization not found or no Gusto connection
- 502 Bad Gateway: Proxy error (token refresh failed, Gusto unreachable)
Error Response Schema
Client IP Resolution
Proxy setsx-gusto-client-ip from:
X-Forwarded-For(rightmost trusted proxy entry)X-Real-IP(fallback)"unknown"if no trusted IP available
TRUST_PROXY_HEADERS=true environment variable is set.
Token Refresh Flow
On 401 response from Gusto API:- Read refresh_token from pf_oauth_tokens
- Exchange refresh_token for new access_token
- Persist both new access_token AND refresh_token (if returned)
- Retry original request once with new access_token
- On failure: return 502 with sanitized error
Security Requirements
- No tokens in client responses
- No stack traces or internal details in errors
- All error messages sanitized before return
- PKCE verification for initial OAuth flow
PII/PHI Logging Guidelines
- ❌ NEVER log: Access tokens, refresh tokens, employee data, SSN fragments
- ✅ ALLOWED in logs: UUIDs (organization_id, integration_id), error codes, timestamps, HTTP status codes
Rate Limiting
Inherits Gusto API rate limits. No additional rate limiting applied. Version: v1.0.0 (PF-65)Last Updated: 2026-02-05
PF-65: Gusto Connection Status
Endpoint:GET /functions/v1/gusto-connection-statusStatus: ✅ Implemented
Auth: Bearer JWT (Supabase session)
Provider: PF (Platform Foundation)
Consumer: Integration Hub UI, HR core
Purpose
Return current Gusto integration status for the caller’s organization.Response Schema (200 OK)
Error Codes
- 401 Unauthorized: Missing or invalid JWT
- 403 Forbidden: User not a member of any organization
Security Requirements
- Only returns status, never credentials
- Organization resolved from JWT, not query params
Last Updated: 2026-02-05
IT Module APIs (Implemented)
IT-07: Dashboard Summary RPC
Endpoint: Database functionit_get_dashboard_summary(p_organization_id UUID)Provider: IT (IT-07 Dashboard & Reporting)
Consumer: IT Dashboard
Status: ✅ Implemented
Last Verified: 2026-02-15 Purpose: Return aggregated IT dashboard metrics in a single call. Invocation Pattern:
useITDashboardSummary(organizationId) in src/cores/it/hooks/useITDashboardSummary.ts
Authentication: JWT required. Validated via it_has_org_access(p_organization_id, auth.uid()) SECURITY DEFINER check.Tenant Enforcement:
p_organization_id validated against caller’s JWT via it_has_org_access(). Returns only data for the specified organization.Permissions:
it.dashboard.view
Error Response Schema:
X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset.Caching:
staleTime: 5min, gcTime: 10min (configured in React hook).Performance SLA: p95 < 500ms.
Idempotency: Read-only RPC — safe to retry.
PII/PHI Logging Guidelines (IT-07)
Theit_get_dashboard_summary RPC and its React hook useITDashboardSummary handle only aggregated counts — no individual-level PII is returned or logged.
| Category | Rule |
|---|---|
| Allowed log fields | organization_id, timestamp, aggregated metric names (e.g., open_tickets, assets_total), request duration, HTTP status |
| Prohibited data | Full names, SSNs, DOB, medical details, credentials, API tokens, IP addresses of end-users |
| Masking / hashing | Not applicable — this RPC returns no PII fields. If future enhancements add user-level data, mask email to j***@example.com and phone to ***-**-1234 |
| Retention & access | Logs retained ≤ 30 days; access restricted to org_admin and platform operators via ACL |
| Log levels | INFO: high-level invocation events (org_id, latency). DEBUG: scrubbed query parameters only. ERROR: non-PII diagnostics (error code, org_id, timestamp) |
Reference: See FA-10/FA-11 PII/PHI Logging Policy in this document for the canonical policy. IT-07 follows the same standards.
IT-09: Change Request List/Detail RPCs
Endpoint 1: Database functionit_get_changes(p_organization_id, p_status, p_limit)Endpoint 2: Database function
it_get_change_detail(p_organization_id, p_change_id)Provider: IT (IT-09 Change Management)
Consumer: IT Change Management UI
Status: ✅ Implemented
Last Verified: 2026-02-15 Purpose: Query change requests with requester/implementer names, and get full detail with approvals and implementations. Invocation Pattern:
useITChanges(organizationId, status?, limit?)insrc/cores/it/hooks/useITChanges.tsuseITChangeDetail(organizationId, changeId)insrc/cores/it/hooks/useITChanges.ts
it_has_org_access(p_organization_id, auth.uid()) SECURITY DEFINER check.Tenant Enforcement:
p_organization_id validated against caller’s JWT via it_has_org_access().Permissions:
it.changes.view
Error Response Schema:
X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset.Caching:
staleTime: 5min, gcTime: 10min (configured in React hooks).Performance SLA: p95 < 500ms.
Idempotency: Read-only RPCs — safe to retry.
it_get_change_detail returns NULL when change not found.
PII/PHI Logging Guidelines (IT-09)
Theit_get_changes and it_get_change_detail RPCs (hooks: useITChanges, useITChangeDetail) return change request metadata including requester/implementer display names joined from pf_profiles.
| Category | Rule |
|---|---|
| Allowed log fields | organization_id, change_id, status, priority, timestamp, request duration, HTTP status |
| Prohibited data | Full names, SSNs, DOB, medical details, credentials, API tokens, raw email addresses |
| Masking / hashing | Requester/implementer names must NOT appear in logs. Use requester_id (UUID) instead. Mask email to j***@domain.com, phone to ***-**-1234 |
| Retention & access | Logs retained ≤ 30 days; access restricted to org_admin and platform operators via ACL |
| Log levels | INFO: invocation events (org_id, change_id, latency). DEBUG: scrubbed filter params (status, limit). ERROR: non-PII diagnostics (error code, change_id, org_id) |
Reference: See FA-10/FA-11 PII/PHI Logging Policy in this document for the canonical policy. IT-09 follows the same standards.
IT-07: Report Generation (Documented)
Endpoint:supabase.functions.invoke('generate-it-report', { body })Provider: IT (IT-07 Dashboard & Reporting)
Consumer: IT Report Builder
Status: ✅ Implemented (existing edge function)
Last Verified: 2026-02-15 Invocation Pattern:
file_url from the response to download the generated report.
Authentication: JWT required (Authorization header). organization_id validated server-side.Tenant Enforcement:
organization_id in body validated against caller’s JWT.Permissions:
it.reports.generate
Error Response Schema:
X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset.Performance SLA: p95 < 2s for report generation.
Idempotency: Idempotent by
run_id — re-invoking with the same run_id returns cached result.
IT-08: Onboarding/Offboarding Hooks (Documented)
Provider: IT (IT-08 Onboarding/Offboarding)Status: ✅ Implemented (existing hooks)
Last Verified: 2026-02-15 Hooks:
usePendingOnboarding(organizationId)— filtersit_onboarding_instancesbyworkflow_type = 'onboarding',status IN ('pending', 'in_progress')usePendingOffboarding(organizationId)— filtersit_onboarding_instancesbyworkflow_type = 'offboarding',status IN ('pending', 'in_progress')
src/cores/it/hooks/useOnboardingInstances.ts
Authentication: JWT required. RLS enforces it_has_org_access(organization_id, auth.uid()).Tenant Enforcement:
organization_id filter applied in query + RLS policy.Permissions:
it.onboarding.viewCaching:
staleTime: 5min, gcTime: 10min (configured in React hooks).Performance SLA: p95 < 500ms.
FA-10/FA-11: Cross-Core Payroll Read Integrations (W-2 / Form 941)
Endpoint 1: Database functionfa_generate_w2_forms(p_org_id UUID, p_tax_year INT)
Endpoint 2: Database function fa_generate_form_941(p_org_id UUID, p_tax_year INT, p_quarter INT)
Provider: FA (FA-10 Tax Compliance / FA-11 Payroll Tax)
Consumer: FA Tax Compliance UI, 1099/W-2 Generation
Status: ✅ Implemented
Last Verified: 2026-02-16
Purpose: Generate W-2 and Form 941 data by reading cross-core HR payroll tables. These functions run with SECURITY DEFINER to access HR tables from the FA core via the Platform Integration Layer pattern.
Cross-Core Tables Read (HR → FA):
hr_payroll_line_items— individual pay line items (wages, deductions, taxes)hr_payroll_runs— payroll run metadata (period, status, finalized date)hr_employees— employee demographic data (name, SSN for W-2 filing)
wages_tips_compensation,federal_tax_withheld,ss_tax_withheld,medicare_tax_withheld,state_tax_withheldsocial_security_wages,medicare_wages- Employee identifiers (for W-2 box population)
organization_id = p_org_id. Only finalized payroll runs (status = 'finalized') for the specified tax year are included. RLS is bypassed via SECURITY DEFINER; the function validates org access internally.
Security: Both functions use SECURITY DEFINER SET search_path = public. Caller’s org membership is validated before execution.
PII/PHI Logging Guidelines (FA-10/FA-11 Payroll)
| Category | Rule |
|---|---|
| Allowed log fields | organization_id, tax_year, quarter, aggregated counts (e.g., w2_count, total_wages_sum), request duration |
| Prohibited data | Employee names, SSNs, DOB, individual wage amounts, bank account numbers, medical deductions |
| Masking / hashing | Employee references in logs must use employee_id (UUID) only. Never log SSN, even partially. Aggregate wage totals are acceptable |
| Retention & access | Logs retained ≤ 30 days; access restricted to org_admin and platform operators |
| Log levels | INFO: generation events (org_id, tax_year, record_count). ERROR: non-PII diagnostics only |
Architecture Reference: These functions follow constitution.md §1.3 (Cross-Core Integration via SECURITY DEFINER RPCs). The FA core does not import HR code; it reads HR tables through documented database functions only.
Planned API Contracts (CL/PM EHR & Practice Management)
Source: EHR_PM_PLANNING_BUNDLE.mdStatus: 📝 Planned (stubs); request/response schemas to be defined in respective CL/PM specs.
Eligibility Check
Endpoint:GET /api/v1/pm/eligibility or POST /api/v1/pm/eligibility (platform layer may wrap external 270/271)Method: GET (by patient_id + payer_id) or POST (batch)
Content-Type:
application/json (request/response)Provider: PM (or platform layer wrapping external 270/271)
Consumers: CL, PM-07, PM-08
Status: 📝 Planned
Spec Reference: PM-02 – Insurance & Eligibility Verification Purpose: Synchronous eligibility verification for a patient and payer. Request/response schema to be defined in PM-02; may wrap clearinghouse 270/271. Authentication & tenant context: JWT required;
organization_id MUST be validated against the authenticated session/claims (do not trust client-provided org_id). All queries scoped by tenant. No cross-tenant access.
TypeScript interfaces (required vs optional):
X-RateLimit-Limit: 60X-RateLimit-Remaining: remaining in current windowX-RateLimit-Reset: Unix timestamp (seconds) when the window resets
Idempotency-Key: <uuid> header to allow safe retries; same key returns same response. Retry 5xx and 429 with exponential backoff (e.g. 1s, 2s, 4s); do not retry 4xx (except 429).
Error response: { error: { code, message, details? } }; status codes: 400 (invalid params), 401 (unauthorized), 403 (forbidden), 404 (patient/payer not found), 429 (rate limit), 500.Permissions:
pm.eligibility.read or equivalent; authorization rules in PM-02.PII/PHI logging: Log only
organization_id, request_id, duration; never log member ID, DOB, or payer-specific identifiers in plain text.Caching: Short TTL (e.g. 5 min) keyed by organization_id + patient_id + payer_id + service_date; invalidate on eligibility update. Example (consumer):
Claim Status Query
Endpoint:GET /api/v1/pm/claim-status?claim_id={id} or POST /api/v1/pm/claim-status (platform layer may wrap 276/277)Method: GET or POST
Content-Type:
application/jsonProvider: PM (or platform layer wrapping clearinghouse 276/277)
Consumers: PM-08, PM-11
Status: 📝 Planned
Spec Reference: PM-15 – Clearinghouse Integration Purpose: Query claim status from clearinghouse. Request/response to be defined in PM-15. Authentication & tenant context: JWT required;
organization_id enforced; RLS/defense-in-depth on claim access.Request:
ClaimStatusRequest — claim_id: uuid, organization_id: uuid.Response (200):
ClaimStatusResponse — claim_id, status, adjudication_date?, denial_reason?, payer_ref?.Error response: Same structure as above; 400, 401, 403, 404, 429, 500.
Permissions:
pm.claims.read; scope by org and optional site.PII/PHI logging: No claim numbers or patient identifiers in logs; only org_id, claim_id (UUID), duration.
Rate limiting & SLA: TBD (e.g. 120/min); p50/p95/p99 and timeout TBD in PM-15.
Retry & idempotency: GET idempotent; retry 5xx/429 with backoff.
Caching: Optional short TTL for status by claim_id.
Example:
const res = await fetch(\/api/v1/pm/claim-status?claim_id={claimId}\`, { headers: { 'Authorization': \`Bearer {token}` } });const data: ClaimStatusResponse = await res.json();`
Resident/Patient Lookup (RH–CL Boundary)
Endpoint:GET /api/v1/platform/patient-lookup?resident_id={uuid} or GET /api/v1/platform/patient-lookup?organization_id={uuid}&external_id={string}Method: GET
Content-Type:
application/jsonProvider: PM or PF (platform layer)
Consumers: RH, CL
Status: 📝 Planned
Spec Reference: Cross-core; no direct RH→CL imports. See EHR_PM_PLANNING_BUNDLE.md §3 (API Contracts List). Purpose: Resolve resident (RH) to patient (PM/CL) identity for cross-core workflows. Schema to be defined in integration spec. Authentication & tenant context: JWT required;
organization_id enforced; caller must have access to resident and patient context.Request: Query params
resident_id or organization_id + external_id (e.g. RH resident id).Response (200):
PatientLookupResponse — patient_id?: uuid, resident_id?: uuid, match_type: 'exact'|'none', demographics_ref?: string.Error response: 400, 401, 403, 404, 429, 500.
Permissions:
platform.patient_lookup.read or equivalent; RH/CL scoped.PII/PHI logging: Log only org_id, resident_id (UUID), match_type; no names or DOB.
Rate limiting & SLA: TBD; conservative limits for lookup.
Retry & idempotency: GET idempotent.
Caching: Optional by resident_id + org_id.
Example:
const res = await fetch(\/api/v1/platform/patient-lookup?resident_id={residentId}\`, { headers: { 'Authorization': \`Bearer {token}` } });const data: PatientLookupResponse = await res.json();`
Patient Demographics (Read)
Endpoint:GET /api/v1/pm/patients/:id (or platform layer equivalent)Method: GET
Content-Type:
application/jsonProvider: PM
Consumers: CL, PM-02, PM-03, PM-07, PM-08
Status: 📝 Planned
Spec Reference: PM-01 – Patient Registration & Demographics Purpose: Read-only patient demographics (USCDI v3–aligned). No PII in logs. Authentication & tenant context: JWT required;
organization_id and RLS enforce tenant scope; path param :id is patient UUID.Request: Path only; optional query
fields for field set.Response (200):
PatientDemographicsResponse — USCDI v3–aligned demographics (name, DOB, gender, identifiers, etc.); shape in PM-01.Error response: 400, 401, 403, 404, 429, 500.
Permissions:
pm.patients.read or equivalent; org/site scoped.PII/PHI logging: Do not log PHI; only org_id, patient_id (UUID), request_id, duration.
Rate limiting & SLA: 200 req/min per org; p95 < 500ms; timeout 10s.
Retry & idempotency: GET idempotent; retry 5xx/429 with backoff.
Caching: Short TTL for demographics by patient_id (e.g. 60s).
Example:
const res = await fetch(\/api/v1/pm/patients/{patientId}\`, { headers: { 'Authorization': \`Bearer {token}` } });const data: PatientDemographicsResponse = await res.json();`
Consent Check (Part 2 / TPO)
Endpoint:POST /api/v1/platform/consent/check (or internal CL service)Method: POST
Content-Type:
application/jsonProvider: CL or platform consent service
Consumers: CL, PM (billing), FW
Status: 📝 Planned
Spec Reference: CL-11 – Consent Management & 42 CFR Part 2 Purpose: Evaluate whether a given access (e.g. TPO, SUD counseling notes, legal proceedings) is permitted for the current user/context. Request/response to be defined in CL-11. Authentication & tenant context: JWT required;
organization_id and patient/resource context required; tenant-scoped policy evaluation.Request:
ConsentCheckRequest — patient_id: uuid, purpose_of_use: string, resource_type?: string, encounter_id?: uuid, organization_id: uuid, user_id?: uuid.Response (200):
ConsentCheckResponse — allowed: boolean, obligations?: string[], denial_reason?: string, audit_id?: string.Error response: 400, 401, 403, 404, 429, 500.
Permissions: Caller must have access to patient and consent service; rules in CL-11.
PII/PHI logging: Log only org_id, patient_id (UUID), purpose_of_use, allowed/denied, audit_id; no consent text or PHI.
Rate limiting & SLA: 300 req/min per org; p95 < 200ms; timeout 5s. Retry 5xx/429 with backoff.
Rate limiting & SLA: TBD; low latency required for UI/API gating.
Retry & idempotency: POST non-idempotent; use idempotency key if supported.
Caching: Policy result cache with short TTL; invalidate on consent change.
Example:
const res = await fetch('/api/v1/platform/consent/check', { method: 'POST', headers: { 'Authorization': \Bearer ${token}`, ‘Content-Type’: ‘application/json’ }, body: JSON.stringify({ patient_id, purpose_of_use: ‘TPO’, organization_id }) });const data: ConsentCheckResponse = await res.json();`
CL-16-EN-01: TEFCA/QHIN Connectivity API (Planned) \
Provider: CL (Clinical & EHR) — CL-16-EN-01Consumers: CL clinical workflows, compliance/audit services, downstream interoperability consumers
Status: 📝 Planned
Ownership: CL-16-EN-01 owns TEFCA/QHIN request orchestration and contract versioning.
Spec Reference: CL-16-EN-01
Integration Doc: CL-16-EN-01-tefca-qhin-connectivity-INTEGRATION.md Contract requirements (all CL-16-EN-01 TEFCA endpoints):
- Authentication: JWT required (
Authorization: Bearer <token>). - Scopes:
cl.tefca.viewrequired for query/history endpoints;cl.tefca.exchangerequired for outbound exchange. - Tenant isolation:
organization_idin request MUST match the authenticated session organization; mismatches fail with403 TENANT_MISMATCH. - Correlation: every request/response includes
correlation_idfor traceability. - PHI/PII logging restrictions: log only
correlation_id,organization_id,purpose_of_use, andstatus; never log patient identifiers, patient match attributes, or clinical payload content. - Error model: standardized responses include one of
400,401,403,404,429,500with stable machine-readable error codes. - Rate limiting/retry: high-volume exchanges are rate-limited per org; clients retry only
429/5xxwith exponential backoff + jitter and honorRetry-Afterwhen present.
400 INVALID_REQUEST- malformed payload, missing required fields, or unsupported enum values.401 UNAUTHENTICATED- missing/invalid JWT.403 CONSENT_DENIED- CL-11 consent is missing/restricted for requested disclosure.403 TENANT_MISMATCH-organization_iddoes not match authenticated tenant context.404 NOT_FOUND- requested exchange/query artifact does not exist in tenant scope.429 RATE_LIMITED- per-org throughput limit exceeded.500 QHIN_CONNECTIVITY_FAILURE- downstream QHIN/transport/service failure.
Endpoint: POST /tefca/qhin/query \
- Purpose: Submit a TEFCA/QHIN patient query request.
- Required fields:
organization_id, patient match attributes,purpose_of_use. - Response shape:
{ status, correlation_id, match_candidates[] }. - Ownership: CL-16-EN-01.
- TODO (schema/version): request/response JSON schema, enum normalization, version lifecycle.
Endpoint: POST /tefca/qhin/exchange \
- Purpose: Execute outbound TEFCA/QHIN exchange with CL-11 consent gates.
- Required fields:
organization_id,patient_id,purpose_of_use, exchange payload reference. - Response shape:
{ status, correlation_id, exchange_log_id }. - Consent binding (required): request MUST execute a CL-11
ConsentCheckRequestwithpatient_id,purpose_of_use, andorganization_idbefore outbound disclosure. - Fail-closed behavior: if consent is absent/restricted, return
403 CONSENT_DENIEDand do not send any outbound payload. - Ownership: CL-16-EN-01.
- TODO (schema/version): consent obligations schema, redisclosure notice metadata, versioned error model.
Endpoint: GET /tefca/qhin/exchanges \
- Purpose: Retrieve org-scoped TEFCA/QHIN exchange history and compliance statuses.
- Required fields:
organization_idand filter parameters (status,direction, date range,qhin_identifier). - Response shape:
{ status, correlation_id, items[], pagination }. - Ownership: CL-16-EN-01.
- TODO (schema/version): pagination contract, filter grammar, response projection profile by API version.
CL-16: FHIR R4 API — Edge Function Facade
Invocation:supabase.functions.invoke('fhir-r4', { body })Content-Type:
application/json (request) / application/fhir+json (response)Provider: CL (Clinical & EHR)
Consumers: PM-12 (patient access), external FHIR clients, HIE partners
Status: 🟡 In Progress (Phase 1)
Spec Reference: CL-16 – FHIR Interoperability & Data Exchange
Integration Doc: CL-16-fhir-interoperability-data-exchange-INTEGRATION.md Purpose: FHIR R4 facade exposing US Core resources (Patient, Condition, MedicationRequest, AllergyIntolerance, Encounter, Observation) via Supabase Edge Functions. Translates internal Encore Health OS data model to FHIR R4 JSON. Consent-gated (CL-11 Part 2). All calls logged to
cl_data_exchange_log.
Architecture Decision (Errata E-1): Supabase Edge Functions as FHIR facade for Phase 1, with migration path to Hybrid (Edge Functions + external FHIR server) for ONC certification.
Endpoint 1: GET /fhir/r4/Patient/:id
Action: get-patientRequired Fields:
organization_id, patient_idSource Table:
pm_patientsFHIR Profile: US Core Patient (http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient) Request:
| Code | OperationOutcome Issue | When |
|---|---|---|
| 400 | invalid | Missing required params |
| 401 | security | No/invalid JWT |
| 403 | forbidden | Cross-tenant access |
| 404 | not-found | Patient not in org |
| 429 | throttled | Rate limit exceeded |
| 500 | exception | Internal error |
Content-Type: application/fhir+json.
Endpoint 2: GET /fhir/r4/Condition
Action: search-conditionRequired Fields:
organization_id, patient_idOptional Fields:
chart_idSource Table:
cl_problemsFHIR Profile: US Core Condition (http://hl7.org/fhir/us/core/StructureDefinition/us-core-condition-problems-health-concerns) Request:
Endpoint 3: GET /fhir/r4/MedicationRequest
Action: search-medication-requestRequired Fields:
organization_id, patient_idSource Table:
cl_medicationsFHIR Profile: US Core MedicationRequest (http://hl7.org/fhir/us/core/StructureDefinition/us-core-medicationrequest) Request:
Endpoint 4: GET /fhir/r4/Patient/:id/$everything
Action: patient-everythingRequired Fields:
organization_id, patient_idSource Tables:
pm_patients, cl_problems, cl_medications, cl_allergies, pm_appointments, cl_order_resultsFHIR Profile: FHIR Bundle (type:
searchset)
Request:
withTimeout() protection.
Cross-Cutting Concerns (All CL-16 Endpoints)
Authentication: JWT required viaAuthorization: Bearer {token}. Validated by validateAuth().Tenant Enforcement:
organization_id required in every request. Verified via verifyOrgAccess() against pf_user_organizations. No cross-tenant data access.RBAC: Caller must have
cl.fhir.read permission (or equivalent clinical access).Consent Enforcement (CL-11): Part 2 SUD data gated by
checkSudConsent(). Fail-closed: if consent check fails, SUD data is excluded.Rate Limiting: 100 req/min per organization for reads; 10 req/min for
$everything. Enforced at Edge Function level.Performance SLA: p95 < 500ms for single-resource reads; p95 < 2s for
$everything.Timeout: 25s per request via
withTimeout().Retry & Idempotency: All GET endpoints are idempotent. Clients may retry on 5xx/429 with exponential backoff.
Caching: No cache for live clinical data.
cl_fhir_resources table available for pre-computed FHIR cache in future phases.
PII/PHI Logging Guidelines:
- Allowed in logs:
organization_id,patient_id(UUID),resource_type,record_count,exchange_type,status,correlation_id,consent_status(boolean),duration_ms - Prohibited in logs: Patient names, DOB, SSN, diagnosis codes, medication names, clinical note content, address details
- Masking: No PHI fields are logged; only IDs and operational metadata
- Retention: Exchange log entries in
cl_data_exchange_logretained per org retention policy; Edge Function stdout/stderr logged for 7 days (Supabase default)
cl_data_exchange_log with: exchange_type, direction (outbound), resource_types, record_count, status, created_by.
Example:
PM-49 API Contracts
Provider: PM-49 (Revenue Cycle Automation Rules Engine) Consumers: PM-49 edge functions (rcm-execute-rules) Status: 📝 Planned Integration Doc: PM-49-revenue-cycle-automation-rules-engine-INTEGRATION.md Spec Reference: PM-49 spec Purpose: Synchronous API contracts for PM-49 automated rule actions that interact with PM-09 (Payment Posting), PM-29 (Denial Management), and PM-45 (Collections).PM-49 → PM-09: Post Adjustment
Callable Interface:- HTTP Endpoint:
POST /rest/v1/rpc/pm_post_adjustment(SECURITY DEFINER RPC) - Alternative: Edge function at
POST /functions/v1/pm-post-adjustment - Required Auth Scope:
pm.adjustments.create - Expected Status Codes: 200 (success), 400 (validation error), 403 (forbidden), 404 (not found), 409 (duplicate), 500 (server error)
- Idempotency Key Field:
rule_execution_id(optional UUID)
CLAIM_NOT_FOUND(404): Claim ID does not existINSUFFICIENT_BALANCE(400): Balance lower than adjustment amountINVALID_ADJUSTMENT_CODE(400): Unrecognized adjustment codeORG_MISMATCH(403): Claim does not belong to organizationDUPLICATE_REQUEST(409): Idempotent duplicate (returns existing adjustment_id in error_message)
rule_execution_id as idempotency key; duplicate requests return 409 with existing adjustment_id
Authentication: Service role or JWT with pm.adjustments.create permission
PM-49 → PM-29: Trigger Denial Resubmission
Callable Interface:- HTTP Endpoint:
POST /rest/v1/rpc/pm_trigger_denial_resubmission(SECURITY DEFINER RPC) - Alternative: Edge function at
POST /functions/v1/pm-trigger-resubmission - Alternative Path:
POST /pm/denials/{denial_id}/resubmit(RESTful route) - Required Auth Scope:
pm.denials.resubmit - Expected Status Codes: 200 (success), 403 (forbidden), 404 (not found), 409 (already resubmitted), 422 (deadline passed), 500 (server error)
- Idempotency Key Field:
rule_execution_id(optional UUID)
DENIAL_NOT_FOUND(404): Denial ID does not existFILING_DEADLINE_PASSED(422): Resubmission past filing deadline (resolved via PF-96)ALREADY_RESUBMITTED(409): Denial already has pending resubmissionORG_MISMATCH(403): Denial does not belong to organizationJURISDICTION_PROFILE_MISSING(500): Unable to resolve filing deadline via PF-96
rule_execution_id as idempotency key
Filing Deadline Resolution: Uses PF-96 pf_resolve_jurisdiction_profile(org_id, site_id) to validate resubmission window. If profile unavailable, fails closed with JURISDICTION_PROFILE_MISSING error.
Authentication: Service role or JWT with pm.denials.resubmit permission
PM-49 → PM-45: Transfer to Collections
Callable Interface:- HTTP Endpoint:
POST /rest/v1/rpc/pm_transfer_to_collections(SECURITY DEFINER RPC) - Alternative: Edge function at
POST /functions/v1/pm-transfer-collections - Alternative Path:
POST /pm/collections/transfer(RESTful route) - Required Auth Scope:
pm.collections.create - Expected Status Codes: 200 (success), 400 (invalid tier), 403 (forbidden), 404 (not found), 409 (already in collections), 422 (ineligible payer), 500 (server error)
- Idempotency Key Field:
rule_execution_id(optional UUID)
ACCOUNT_NOT_FOUND(404): Account/claim ID does not existALREADY_IN_COLLECTIONS(409): Account already assigned to collections tierINELIGIBLE_PAYER(422): Payer type excluded from collections (e.g., Medicaid in some states)ORG_MISMATCH(403): Account does not belong to organizationINVALID_TIER(400): Unrecognized collections tier
rule_execution_id as idempotency key
Authentication: Service role or JWT with pm.collections.create permission
PM-49 Published Event: pm_rcm_rule_executed
Purpose: PM-11 dashboard consumes this event for RCM automation metrics
Event Schema:
Related Documentation
- Platform Integration Layers - Platform layer integrations
- Event Contracts - Event-based integrations
- IT Integration Contracts - IT module integration contracts
- Integration Examples - Code examples
- Constitution - Engineering guardrails
PF-63: Entra ID Deep Integration Edge Functions
Status: ✅ ImplementedSpec Reference: PF-63 (Entra ID Integration)
Last Updated: 2026-02-21
Edge Function 1: entra-employee-presence
Invocation: supabase.functions.invoke('entra-employee-presence', { body })Provider: PF (Platform Foundation)
Consumer: HR employee views, dashboards
JWT Required: Yes Actions:
| Action | Required Fields | Response |
|---|---|---|
get-single | organization_id, employee_id | { presence: { id, availability, activity } } |
get-batch | organization_id, employee_ids[] | { presenceMap: Record<empId, presence> } |
get-ooo | organization_id, employee_id | { ooo: { isOOO, endDate } } |
verifyOrgAccess(). OOO message content redacted (PHI).Performance SLA: p95 < 2s (single), < 5s (batch up to 650).
Rate Limit: Per-organization, delegated to Graph API limits.
Edge Function 2: entra-teams-notify
Invocation: supabase.functions.invoke('entra-teams-notify', { body })Provider: PF (Platform Foundation)
Consumer:
event-consumer, internal servicesJWT Required: Yes (typically service-role) Request:
{ success: true, correlationId }Security: JWT +
verifyOrgAccess(). HTML escaping on all template values.Performance SLA: p95 < 3s.
Edge Function 3: entra-sharepoint-documents
Invocation: supabase.functions.invoke('entra-sharepoint-documents', { body })Provider: PF (Platform Foundation)
Consumer: SharePoint document browser UI
JWT Required: Yes Actions:
| Action | Required Fields | Response |
|---|---|---|
list | organization_id, site_id, folder_id? | { items: SharePointItem[] } |
upload | organization_id, site_id, file_name, file_content (base64) | { item } |
download | organization_id, site_id, item_id | { downloadUrl } |
create-folder | organization_id, site_id, folder_name | { folder } |
search | organization_id, site_id, query | { items: SharePointItem[] } |
verifyOrgAccess(). Max upload: 50MB. Action parameter sanitized.Performance SLA: p95 < 3s (list/search), < 10s (upload).
Edge Function 4: entra-teams-activity
Invocation: supabase.functions.invoke('entra-teams-activity', { body })Provider: PF (Platform Foundation)
Consumer: Notification pipeline
JWT Required: Yes Request:
{ success: true } or { success: true, skipped: true, reason: string }Skip Conditions: Feature disabled, below priority threshold, no Entra ID for user.
Security: JWT +
verifyOrgAccess(). Requires Azure Bot registration.Performance SLA: p95 < 3s.
HR-34: Contractor 1099 Totals RPC
Provider: HR (Workforce) — HR-34 Consumer: HR-PAY-04 (Tax Forms), HR-34 UI (1099 dashboard) Status: ✅ Implemented Integration Doc: HR-34 Integration Database function:hr_get_contractor_1099_totals(p_organization_id uuid, p_tax_year integer)
Returns: SETOF RECORD (contractor_id uuid, total_amount numeric, entry_count bigint)
Purpose: Aggregates all approved (approval_status = 'approved') time entry amounts for contractors in a given organization and tax year. Used by HR-PAY-04 to produce 1099-NEC input data.
Auth: authenticated role + hr_has_org_access(p_organization_id, auth.uid()) enforced inside the SECURITY DEFINER function. Callers must also hold hr.contractor.tax_id.read permission for tax ID display in the UI.
Request (logical):
p_organization_id(UUID): Tenant contextp_tax_year(INTEGER): Calendar year to aggregate (e.g. 2025)
total_amount is the sum of hr_contractor_time_entries.amount where approval_status = 'approved'. entry_count is the count of such entries.
Idempotency: Read-only function; re-runs return same results for same inputs.
Hook: useContractor1099Totals(taxYear) in src/cores/hr/hooks/contractors/useContractor1099Totals.ts
Next Review: 2026-06-30 (Quarterly)