Developers
Kreto API reference
The compliance intelligence API — classify notices, cross-check payroll, drive resolutions and more. Every operation below is generated from the same OpenAPI specification that powers the Kreto SDK, CLI and MCP server.
Authentication
UI clients authenticate with a Supabase cookie session and need no setup. Partner and machine-to-machine integrations use a tenant-scoped Bearer token. Create and manage keys through POST /api/api-keys. Every request is isolated to the key’s tenant via row-level security, and each key carries an explicit scope array — an operation only succeeds if the key holds every scope it lists.
Available scopes (8) — grant a key only the scopes its integration needs:
admin.readaudit.reademployers.reademployers.writenotices.readnotices.writepayroll.readpayroll.writeAnalytics1
GET/api/analytics/predictionsEntity risk predictions
Risk predictions for an entity: SUI rate-change forecast, ACA penalty risk (when FTE >= 40), and overall risk profile aggregating open/overdue notices + active state count. CPA-class roles only on cookie sessions; Bearer keys gate via `notices.read`.
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
entity_id | query | string · uuid | required | — |
Responses
- 200Risk predictions
AnalyticsPredictionsResponseField Type Required Description entityobjectrequired — riskProfileobjectrequired — suiPredictionobjectrequired — acaRiskobjectrequired — - 400Validation error
MiscValidationErrorResponse - 401Unauthorized
MiscUnauthorizedResponse - 403Forbidden — CPA access required
MiscUnauthorizedResponse - 404Entity not found
MiscNotFoundResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
API Keys4
GET/api/api-keysList API keys for the caller's tenant
Returns all API keys (active + revoked) for the authenticated CPA's tenant. Response NEVER includes plaintext or key_hash — only the publicly safe key_prefix + metadata.
Responses
- 200List of API keys
ListApiKeysResponseField Type Required Description keysarray<PublicApiKey>required — - 401Unauthorized
ApiKeysNotFoundResponse
POST/api/api-keysIssue a new API key
Create a new API key for the authenticated CPA's tenant. Plaintext is returned ONCE in the response (`plaintext` field) — store it securely; subsequent GET calls return only the masked metadata. Optional `scopes` array narrows the key's authority; NULL/omitted = full tenant scope.
Request body CreateApiKeyBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
name | string | required | — |
scopes | array<enum: "notices.read" | "employers.read" | "payroll.read" | "audit.read" | …> | optional | Optional scope array. NULL or omitted = full tenant scope (v1 default). |
expires_at | string · date-time | optional | Optional expiry. NULL = never expires (operator-revocation only). |
Responses
- 201Key issued. Plaintext returned ONCE; store it now — it cannot be retrieved again.
IssuedApiKeyField Type Required Description idstring · uuidrequired — tenant_idstring · uuidrequired — key_prefixstringrequired — namestringrequired — scopesarray<enum: "notices.read" | "employers.read" | "payroll.read" | "audit.read" | …>required — created_by_user_idstring · uuidrequired — created_atstring · date-timerequired — last_used_atstring · date-timerequired — revoked_atstring · date-timerequired — expires_atstring · date-timerequired — plaintextstringrequired — warningenum: "This is the ONLY time the plaintext is shown. Store it securely now."required — - 400Validation error (Zod issues array in body)
ApiKeysValidationErrorResponse - 401Unauthorized — caller is not authenticated as a CPA
ApiKeysNotFoundResponse
GET/api/api-keys/{id}Fetch a single API key's metadata
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | — |
Responses
- 200Key metadata
objectField Type Required Description keyPublicApiKeyrequired — - 404Key not found in your tenant
ApiKeysNotFoundResponse
DELETE/api/api-keys/{id}Revoke an API key
Soft-delete via `revoked_at`. Idempotent — re-revoking returns the existing revocation timestamp. Optional body { reason: string } for audit context.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | — |
Request body object
| Field | Type | Required | Description |
|---|---|---|---|
reason | string | optional | — |
Responses
- 200Key revoked (or already revoked — idempotent)
RevokeApiKeyResponseField Type Required Description revokedbooleanrequired — already_revokedbooleanrequired — revoked_atstring · date-timeoptional — keyPublicApiKeyoptional — - 404Key not found in your tenant
ApiKeysNotFoundResponse
Audit1
GET/api/auditList audit events
Fetch tenant audit events, optionally filtered by entity_id. CPA-class roles only on cookie sessions; Bearer keys gate via `audit.read`.
audit.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
limit | query | integer | optional | — |
entity_id | query | string · uuid | optional | — |
Responses
- 200Audit events
AuditEventsResponseField Type Required Description okenum: truerequired — eventsarray<AuditEvent>required — - 401Unauthorized
MiscUnauthorizedResponse - 403Forbidden — CPA access required
MiscUnauthorizedResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
Compliance17
POST/api/compliance/digestTrigger compliance digest
Manually trigger a weekly compliance digest email. CPA-class roles only on cookie sessions; Bearer keys gate via `admin.read` scope.
admin.readResponses
- 200Digest dispatched
ComplianceDigestResponseField Type Required Description successenum: truerequired — sentintegeroptional — skippedintegeroptional — digest_idstringoptional — - 401Unauthorized
ComplianceUnauthorizedResponse - 403Forbidden — CPA access required / missing scope
ComplianceUnauthorizedResponse - 429Rate limit exceeded
ComplianceRateLimitResponse - 500Server error
ComplianceUnauthorizedResponse
GET/api/compliance/score-historyGet compliance score history
Returns the most recent 12 score-history entries for the caller's tenant (or for a specific entity when entity_id is supplied).
audit.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
entity_id | query | string · uuid | optional | — |
Responses
- 200Score history
ComplianceScoreHistoryResponseField Type Required Description historyarray<ComplianceScoreHistoryEntry>required — - 400Validation error
ComplianceValidationErrorResponse - 401Unauthorized
ComplianceUnauthorizedResponse - 403Forbidden — missing required scope
ComplianceUnauthorizedResponse - 429Rate limit exceeded
ComplianceRateLimitResponse
GET/api/compliance/roi-summaryGet YTD ROI summary
Returns YTD savings, penalties avoided, time saved, and notice count derived from `roi_events` for the caller's tenant.
audit.readResponses
- 200YTD ROI summary
ComplianceRoiSummaryResponseField Type Required Description ytd_savingsintegerrequired — ytd_penalties_avoidedintegerrequired — ytd_time_saved_hoursintegerrequired — ytd_notices_processedintegerrequired — - 401Unauthorized
ComplianceUnauthorizedResponse - 403Forbidden — missing required scope
ComplianceUnauthorizedResponse - 429Rate limit exceeded
ComplianceRateLimitResponse
GET/api/compliance/intelligence-scoreGet compliance intelligence score
Returns the Compliance Intelligence Score either for a single entity (when entity_id is supplied) or aggregated across all of the caller's tenant's entities.
audit.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
entity_id | query | string · uuid | optional | — |
Responses
- 200Score (single or aggregate)
one of (ComplianceSingleEntityScoreResponse · ComplianceIntelligenceScore) - 400Validation error
ComplianceValidationErrorResponse - 401Unauthorized
ComplianceUnauthorizedResponse - 403Forbidden — missing required scope
ComplianceUnauthorizedResponse - 429Rate limit exceeded
ComplianceRateLimitResponse - 500Server error
ComplianceUnauthorizedResponse
GET/api/compliance-score/{entityId}Get single-entity score (legacy)
Legacy path: returns the Compliance Intelligence Score for a given entity. Tenant-scoped on the entity verification (KRT-1479 P4e.1 Senior-Dev-Override fix).
audit.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
entityId | path | string · uuid | required | Employer entity UUID |
Responses
- 200Compliance intelligence score
object - 400Validation error
ComplianceValidationErrorResponse - 401Unauthorized
ComplianceUnauthorizedResponse - 403Forbidden — missing required scope
ComplianceUnauthorizedResponse - 404Entity not found in caller's tenant
ComplianceNotFoundResponse - 429Rate limit exceeded
ComplianceRateLimitResponse - 500Server error
ComplianceUnauthorizedResponse
GET/api/compliance/aca-summaryGet ACA summary
Returns ACA (Applicable Large Employer) status + penalty exposure per entity. Primary FTE source: payroll_pay_periods; fallback chain through payroll_records → onboarding range → entity.employee_count.
audit.readResponses
- 200ACA summary by entity
ComplianceAcaSummaryResponseField Type Required Description employeesintegerrequired — aleStatusenum: "applicable" | "not_applicable"required — dataQualityenum: "payroll" | "estimate"required — entitiesarray<ComplianceAcaEntity>required — - 401Unauthorized
ComplianceUnauthorizedResponse - 403Forbidden — missing required scope
ComplianceUnauthorizedResponse - 429Rate limit exceeded
ComplianceRateLimitResponse - 500Server error
ComplianceUnauthorizedResponse
GET/api/compliance/benefitsList benefits compliance
List benefits compliance records for all tenant entities for a given plan year (defaults to current year).
audit.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
year | query | string | optional | Plan year |
Responses
- 200Benefits list
ComplianceBenefitsListResponseField Type Required Description recordsarray<object>required — yearintegerrequired — - 401Unauthorized
ComplianceUnauthorizedResponse - 403Forbidden — missing required scope
ComplianceUnauthorizedResponse - 429Rate limit exceeded
ComplianceRateLimitResponse
POST/api/compliance/benefitsUpsert benefits compliance record
Upsert a benefits compliance record for an entity + plan year. Tenant-scoped on the entity verification (already correct pre-Phase-4).
notices.writeRequest body ComplianceBenefitsPostBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
entity_id | string · uuid | required | — |
plan_year | integer | required | — |
plan_type | string | optional | — |
carrier_name | string | optional | — |
plan_participants | integer | optional | — |
rxdc_completed | boolean | optional | — |
rxdc_completed_date | string · date | optional | — |
gag_clause_filed | boolean | optional | — |
gag_clause_filed_date | string · date | optional | — |
gag_clause_confirmation | string | optional | — |
medicare_part_d_sent | boolean | optional | — |
medicare_part_d_sent_date | string · date | optional | — |
chip_notice_sent | boolean | optional | — |
chip_notice_sent_date | string · date | optional | — |
form_5500_required | boolean | optional | — |
form_5500_filed | boolean | optional | — |
form_5500_filed_date | string · date | optional | — |
cobra_documented | boolean | optional | — |
Responses
- 200Record upserted
objectField Type Required Description recordBenefitsRecordrequired — - 400Validation error
ComplianceValidationErrorResponse - 401Unauthorized
ComplianceUnauthorizedResponse - 403Forbidden — missing required scope
ComplianceUnauthorizedResponse - 404Entity not found in caller's tenant
ComplianceNotFoundResponse - 429Rate limit exceeded
ComplianceRateLimitResponse - 500Server error
ComplianceUnauthorizedResponse
GET/api/compliance/pfml-checkCheck PFML compliance gaps
PFML enrollment gap analysis for tenant entities. client_user role (cookie session) scoped to assigned entities; CPA-class + Bearer keys see all tenant entities.
audit.readResponses
- 200PFML gap analysis
CompliancePfmlResponseField Type Required Description entitiesarray<CompliancePfmlResult>required — summaryobjectrequired — - 401Unauthorized
ComplianceUnauthorizedResponse - 403Forbidden — missing required scope
ComplianceUnauthorizedResponse - 429Rate limit exceeded
ComplianceRateLimitResponse - 500Server error
ComplianceUnauthorizedResponse
GET/api/compliance/wage-hour-riskGet wage & hour risk scores
Returns wage & hour risk scores per entity (state minimum wage check, overtime policy gaps, exempt-employee threshold, contractor risk).
audit.readResponses
- 200Risk scores per entity
ComplianceWageHourResponseField Type Required Description entitiesarray<ComplianceWageHourEntity>required — federalMinimumWagenumberrequired — overtimeSalaryThresholdnumberrequired — errorstringoptional — - 401Unauthorized
ComplianceUnauthorizedResponse - 403Forbidden — missing required scope
ComplianceUnauthorizedResponse - 429Rate limit exceeded
ComplianceRateLimitResponse
GET/api/compliance-monitorGet compliance monitor profiles
Returns compliance profiles for all employers (sorted worst-first). client_user role scoped to assigned entities; CPA-class + Bearer keys see all tenant entities.
audit.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
entity_id | query | string · uuid | optional | Filter to a single entity (must be authorized) |
Responses
- 200Compliance profiles
ComplianceMonitorResponseField Type Required Description profilesarray<object>required — - 400Validation error
ComplianceValidationErrorResponse - 401Unauthorized
ComplianceUnauthorizedResponse - 403Forbidden — entity access denied / missing scope
ComplianceUnauthorizedResponse - 429Rate limit exceeded
ComplianceRateLimitResponse - 500Server error
ComplianceUnauthorizedResponse
PATCH/api/compliance/credential-alerts/{id}/acknowledgeAcknowledge credential-refresh alert
Dismiss a credential_refresh_alerts row (KRT-1288). 404 covers not-found / already-acknowledged / auto-resolved equally.
notices.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Alert UUID |
Responses
- 200Acknowledged
ComplianceCredentialAlertsAcknowledgeResponseField Type Required Description alertobjectrequired — - 400Validation error
ComplianceValidationErrorResponse - 401Unauthorized
ComplianceUnauthorizedResponse - 403Forbidden — CPA access required / missing scope
ComplianceUnauthorizedResponse - 404Alert not found or already handled
ComplianceNotFoundResponse - 429Rate limit exceeded
ComplianceRateLimitResponse - 500Server error
ComplianceUnauthorizedResponse
PATCH/api/compliance/recommendations/{id}/acknowledgeAcknowledge state-registration recommendation
Dismiss a state_registration_recommendations row (KRT-1216 PR-D).
notices.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Recommendation UUID |
Responses
- 200Acknowledged
ComplianceRecommendationsAcknowledgeResponseField Type Required Description recommendationobjectrequired — - 400Validation error
ComplianceValidationErrorResponse - 401Unauthorized
ComplianceUnauthorizedResponse - 403Forbidden — CPA access required / missing scope
ComplianceUnauthorizedResponse - 404Recommendation not found or already acknowledged
ComplianceNotFoundResponse - 429Rate limit exceeded
ComplianceRateLimitResponse - 500Server error
ComplianceUnauthorizedResponse
GET/api/compliance/payroll-tax-analysisGet payroll-tax analysis
Calculate expected federal payroll taxes (SS, Medicare, FUTA, 941, 940) per entity from Finch / payroll_records / employee-count fallback chain. Per-employee detail is stripped from response (PII).
audit.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
entity_id | query | string · uuid | optional | — |
Responses
- 200Payroll-tax analysis
CompliancePayrollTaxAnalysisResponseField Type Required Description entitiesarray<CompliancePayrollTaxEntity>required — summaryobjectrequired — - 400Validation error
ComplianceValidationErrorResponse - 401Unauthorized
ComplianceUnauthorizedResponse - 403Forbidden — missing required scope
ComplianceUnauthorizedResponse - 429Rate limit exceeded
ComplianceRateLimitResponse - 500Server error
ComplianceUnauthorizedResponse
POST/api/compliance/payroll-tax-analysisAnalyze payroll-tax compliance
Compare expected payroll-tax liability against quarterly deposit input. Returns expected + compliance comparison + dataSource.
audit.readRequest body CompliancePayrollTaxAnalysisPostBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
entity_id | string · uuid | required | — |
deposits | array<object> | required | — |
Responses
- 200Comparison result
CompliancePayrollTaxAnalysisPostResponseField Type Required Description expectedobjectrequired — complianceobjectrequired — dataSourceenum: "finch" | "payroll" | "estimate"required — - 400Validation error
ComplianceValidationErrorResponse - 401Unauthorized
ComplianceUnauthorizedResponse - 403Forbidden — missing required scope
ComplianceUnauthorizedResponse - 404Entity not found in caller's tenant
ComplianceNotFoundResponse - 429Rate limit exceeded
ComplianceRateLimitResponse - 500Server error
ComplianceUnauthorizedResponse
GET/api/compliance/alertsGet unified compliance alerts
Returns a unified compliance-alerts list across 5 sources (compliance_checks, urgent + overdue + needs-review notices, state_registration_recommendations, credential_refresh_alerts).
audit.readResponses
- 200Compliance alerts
ComplianceAlertsResponseField Type Required Description alertsarray<ComplianceAlert>required — - 401Unauthorized
ComplianceUnauthorizedResponse - 403Forbidden — missing required scope
ComplianceUnauthorizedResponse - 429Rate limit exceeded
ComplianceRateLimitResponse
GET/api/compliance-calendarGet compliance calendar
Returns notices + work_items with deadlines, grouped into overdue / thisWeek / thisMonth / future buckets. Tenant-scoped (P4e.3 Senior-Dev-Override fix).
audit.readResponses
- 200Grouped deadline calendar
ComplianceCalendarResponseField Type Required Description overduearray<ComplianceCalendarItem>required — thisWeekarray<ComplianceCalendarItem>required — thisMontharray<ComplianceCalendarItem>required — futurearray<ComplianceCalendarItem>required — summaryobjectrequired — - 401Unauthorized
ComplianceUnauthorizedResponse - 403Forbidden — missing required scope
ComplianceUnauthorizedResponse - 429Rate limit exceeded
ComplianceRateLimitResponse - 500Server error
ComplianceUnauthorizedResponse
Connections10
GET/api/connectionsList connections
Returns the unified connection list (data_connections + finch_connections) scoped to the caller's tenant. Sensitive config fields (encrypted refresh tokens, token expiries) are stripped.
payroll.readResponses
- 200Connections list
ConnectionListResponse - 401Unauthorized
ConnectionsUnauthorizedResponse - 403Forbidden — missing required scope
ConnectionsUnauthorizedResponse - 429Rate limit exceeded
ConnectionsRateLimitResponse - 500Server error
ConnectionsUnauthorizedResponse
POST/api/connections/{id}Trigger connection sync
Trigger a manual sync. Body: `{ action: "sync" }`. Enqueues a connection_sync job; the worker picks it up.
payroll.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Connection UUID |
Request body ConnectionPostBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
action | enum: "sync" | required | — |
Responses
- 200Sync enqueued
ConnectionSyncResponseField Type Required Description okenum: truerequired — messageenum: "Sync enqueued"required — - 400Validation error / wrong status / missing token
ConnectionsValidationErrorResponse - 401Unauthorized
ConnectionsUnauthorizedResponse - 403Forbidden — missing required scope
ConnectionsUnauthorizedResponse - 404Connection not found in caller's tenant
ConnectionsNotFoundResponse - 429Rate limit exceeded
ConnectionsRateLimitResponse - 500Server error
ConnectionsUnauthorizedResponse
DELETE/api/connections/{id}Disconnect connection
Disconnect a connection: revoke the Google OAuth token (best-effort) and mark the row as `revoked`. Sensitive config fields are cleared.
payroll.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Connection UUID |
Responses
- 200Disconnected
ConnectionDisconnectResponseField Type Required Description okenum: truerequired — messageenum: "Disconnected"required — - 400Validation error
ConnectionsValidationErrorResponse - 401Unauthorized
ConnectionsUnauthorizedResponse - 403Forbidden — missing required scope
ConnectionsUnauthorizedResponse - 404Connection not found in caller's tenant
ConnectionsNotFoundResponse - 429Rate limit exceeded
ConnectionsRateLimitResponse - 500Server error
ConnectionsUnauthorizedResponse
GET/api/connections/finch/statusGet Finch connection status
Returns the Finch connection status + recent sync logs for an entity.
payroll.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
entity_id | query | string · uuid | required | Entity UUID (required) |
Responses
- 200Status + sync logs
FinchStatusResponseField Type Required Description connectedbooleanrequired — statusstringrequired — connectionobjectrequired — recent_syncsarray<FinchSyncLog>optional — - 400Validation error
ConnectionsValidationErrorResponse - 401Unauthorized
ConnectionsUnauthorizedResponse - 403Forbidden — missing required scope
ConnectionsUnauthorizedResponse - 429Rate limit exceeded
ConnectionsRateLimitResponse
GET/api/connections/{id}/foldersList provider folders
List folders from the connected provider (Google Drive or Dropbox). Returns selectedFolderIds from current config so the UI can render the checkbox state.
payroll.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Connection UUID |
Responses
- 200Folder list + selected IDs
ConnectionFoldersGetResponseField Type Required Description foldersarray<ConnectionFolderEntry>required — selectedFolderIdsarray<string>required — - 400Validation error
ConnectionsValidationErrorResponse - 401Unauthorized
ConnectionsUnauthorizedResponse - 403Forbidden — missing required scope
ConnectionsUnauthorizedResponse - 404Connection not found in caller's tenant
ConnectionsNotFoundResponse - 429Rate limit exceeded
ConnectionsRateLimitResponse - 500Server error
ConnectionsUnauthorizedResponse
PUT/api/connections/{id}/foldersSave selected folders
Save selected watched-folder IDs to the connection config.
payroll.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Connection UUID |
Request body ConnectionFoldersPutBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
folderIds | array<string> | required | — |
Responses
- 200Saved
ConnectionFoldersPutResponseField Type Required Description savedenum: truerequired — folderIdsarray<string>required — - 400Validation error
ConnectionsValidationErrorResponse - 401Unauthorized
ConnectionsUnauthorizedResponse - 403Forbidden — missing required scope
ConnectionsUnauthorizedResponse - 404Connection not found in caller's tenant
ConnectionsNotFoundResponse - 429Rate limit exceeded
ConnectionsRateLimitResponse - 500Server error
ConnectionsUnauthorizedResponse
GET/api/connections/{id}/watchList watched folders
List active watched folders for a connection.
payroll.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Connection UUID |
Responses
- 200Watched folders
ConnectionWatchListResponseField Type Required Description foldersarray<object>required — - 400Validation error
ConnectionsValidationErrorResponse - 401Unauthorized
ConnectionsUnauthorizedResponse - 403Forbidden — missing required scope
ConnectionsUnauthorizedResponse - 429Rate limit exceeded
ConnectionsRateLimitResponse
POST/api/connections/{id}/watchStart watching folder
Start watching a folder for inbound notice intake. Verifies that both the connection and target entity belong to the caller's tenant.
payroll.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Connection UUID |
Request body ConnectionWatchPostBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
folder_id | string | required | — |
folder_name | string | required | — |
folder_path | string | optional | — |
entity_id | string · uuid | required | — |
Responses
- 200Now watching
ConnectionWatchPostResponseField Type Required Description watched_folderobjectrequired — entity_namestringrequired — messagestringrequired — - 400Validation error
ConnectionsValidationErrorResponse - 401Unauthorized
ConnectionsUnauthorizedResponse - 403Forbidden — missing required scope
ConnectionsUnauthorizedResponse - 404Connection or entity not found
ConnectionsNotFoundResponse - 429Rate limit exceeded
ConnectionsRateLimitResponse - 500Server error
ConnectionsUnauthorizedResponse
DELETE/api/connections/{id}/watchStop watching folder
Stop watching a folder (soft-delete via is_active=false).
payroll.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Connection UUID |
Request body ConnectionWatchDeleteBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
watched_folder_id | string · uuid | required | — |
Responses
- 200Stopped
objectField Type Required Description successenum: truerequired — - 400Validation error
ConnectionsValidationErrorResponse - 401Unauthorized
ConnectionsUnauthorizedResponse - 403Forbidden — missing required scope
ConnectionsUnauthorizedResponse - 429Rate limit exceeded
ConnectionsRateLimitResponse - 500Server error
ConnectionsUnauthorizedResponse
POST/api/connections/finch/syncTrigger Finch sync
Trigger a manual Finch sync. Enqueues a finch_sync job; skips if another sync is already pending/running. Cookie sessions go through the Stripe subscription gate; Bearer keys bypass.
payroll.writeRequest body FinchSyncPostBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
entity_id | string · uuid | required | — |
Responses
- 200Sync enqueued or already in progress
FinchSyncResponseField Type Required Description messagestringrequired — job_idstring · uuidoptional — - 400Validation error / connection inactive
ConnectionsValidationErrorResponse - 401Unauthorized
ConnectionsUnauthorizedResponse - 402Subscription required (cookie sessions only)
ConnectionsUnauthorizedResponse - 403Forbidden — missing required scope
ConnectionsUnauthorizedResponse - 404No Finch connection for entity
ConnectionsNotFoundResponse - 429Rate limit exceeded
ConnectionsRateLimitResponse - 500Server error
ConnectionsUnauthorizedResponse
Dashboard2
GET/api/dashboard/summaryDashboard summary
Aggregated dashboard metrics (KRT-473): notice counts, task counts, fine amounts, and configured deadline window.
notices.readResponses
- 200Summary metrics
DashboardSummaryResponseField Type Required Description noticesobjectrequired — tasksobjectrequired — finesobjectrequired — deadline_window_daysintegerrequired — - 401Unauthorized
MiscUnauthorizedResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
GET/api/dashboard/trendsDashboard trends
Dashboard trends over a configurable window. Optionally filter to a single entity_id.
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
days | query | integer | optional | — |
entity_id | query | string · uuid | optional | — |
Responses
- 200Trends
DashboardTrendsResponseSchemaField Type Required Description trendsarray<object>required — range_daysintegerrequired — - 401Unauthorized
MiscUnauthorizedResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
Documents15
GET/api/documents/{id}/auditGet document audit trail
Returns the document's audit trail — signature events, sends, voids, and view events with actor + timestamp + IP/user-agent context.
audit.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Document UUID |
Responses
- 200Audit trail
DocumentAuditResponseField Type Required Description audit_trailarray<DocumentAuditEntry>required — - 400Validation error
DocumentValidationErrorResponse - 401Unauthorized
DocumentUnauthorizedResponse - 403Forbidden — missing required scope
DocumentUnauthorizedResponse - 429Rate limit exceeded
DocumentRateLimitResponse - 500Server error
DocumentUnauthorizedResponse
GET/api/documents/{id}/signaturesList document signatures
Returns all recorded signatures for a document.
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Document UUID |
Responses
- 200Signatures list
DocumentSignaturesResponseField Type Required Description signaturesarray<DocumentSignatureRecord>required — - 400Validation error
DocumentValidationErrorResponse - 401Unauthorized
DocumentUnauthorizedResponse - 403Forbidden — missing required scope
DocumentUnauthorizedResponse - 429Rate limit exceeded
DocumentRateLimitResponse - 500Server error
DocumentUnauthorizedResponse
POST/api/documents/{id}/sendSend document to recipient
Send a document to a recipient via email. RLS enforces document ownership; sender_id is recorded for the audit trail.
notices.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Document UUID |
Request body DocumentSendBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
recipient_email | string · email | required | — |
recipient_name | string | required | — |
message | string | optional | — |
Responses
- 200Sent
DocumentSendResponseField Type Required Description documentobjectrequired — - 400Validation error
DocumentValidationErrorResponse - 401Unauthorized
DocumentUnauthorizedResponse - 403Forbidden — missing required scope
DocumentUnauthorizedResponse - 429Rate limit exceeded
DocumentRateLimitResponse - 500Server error
DocumentUnauthorizedResponse
POST/api/documents/{id}/voidVoid document
Void a document with a reason. Voided documents cannot be re-sent or re-signed; the audit trail records the void event.
notices.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Document UUID |
Request body DocumentVoidBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
reason | string | required | — |
Responses
- 200Voided
DocumentSendResponseField Type Required Description documentobjectrequired — - 400Validation error
DocumentValidationErrorResponse - 401Unauthorized
DocumentUnauthorizedResponse - 403Forbidden — missing required scope
DocumentUnauthorizedResponse - 429Rate limit exceeded
DocumentRateLimitResponse - 500Server error
DocumentUnauthorizedResponse
POST/api/documents/{id}/signSign document
Record a signature on a document. Captures signer name + email + IP + user-agent for the audit trail. 4 signature methods supported.
notices.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Document UUID |
Request body DocumentSignBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
signer_name | string | required | — |
signer_email | string · email | required | — |
signer_role | string | optional | — |
signature_data | string | optional | — |
signature_method | enum: "drawn" | "typed" | "uploaded" | "click_to_sign" | … | optional | — |
Responses
- 201Signature recorded
DocumentSignResponseField Type Required Description signatureDocumentSignatureRecordrequired — - 400Validation error
DocumentValidationErrorResponse - 401Unauthorized
DocumentUnauthorizedResponse - 403Forbidden — missing required scope
DocumentUnauthorizedResponse - 429Rate limit exceeded
DocumentRateLimitResponse - 500Server error
DocumentUnauthorizedResponse
GET/api/documents/statsGet document counts
Returns document counts by status (total / pending / signed / expired) for the caller's tenant. Falls back to count-only when the documents.status column is missing.
notices.readResponses
- 200Stats by status
DocumentStatsResponseField Type Required Description totalintegerrequired — pendingintegerrequired — signedintegerrequired — expiredintegerrequired — - 401Unauthorized
DocumentUnauthorizedResponse - 403Forbidden — missing required scope
DocumentUnauthorizedResponse - 429Rate limit exceeded
DocumentRateLimitResponse - 500Server error
DocumentUnauthorizedResponse
GET/api/documents/collectionGet document-collection progress by entity
Returns document_requests grouped by entity, with progress counts (items_total / items_complete) and derived status (complete / overdue / in_progress).
notices.readResponses
- 200Grouped collection requests
DocumentCollectionResponseField Type Required Description requestsarray<DocumentCollectionGroup>required — - 401Unauthorized
DocumentUnauthorizedResponse - 403Forbidden — missing required scope
DocumentUnauthorizedResponse - 429Rate limit exceeded
DocumentRateLimitResponse - 500Server error
DocumentUnauthorizedResponse
GET/api/documentsList documents
List documents with optional filters (requestId, entityId, date range, includeDeleted) and pagination.
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
requestId | query | string · uuid | optional | — |
entityId | query | string · uuid | optional | — |
startDate | query | string · date-time | optional | — |
endDate | query | string · date-time | optional | — |
limit | query | string | optional | — |
offset | query | string | optional | — |
includeDeleted | query | enum: "true" | "false" | optional | — |
Responses
- 200Documents list
DocumentListResponseField Type Required Description documentsarray<DocumentRecord>required — countintegerrequired — limitintegerrequired — offsetintegerrequired — - 400Validation error
DocumentValidationErrorResponse - 401Unauthorized
DocumentUnauthorizedResponse - 403Forbidden — missing required scope
DocumentUnauthorizedResponse - 429Rate limit exceeded
DocumentRateLimitResponse - 500Server error
DocumentUnauthorizedResponse
GET/api/documents/{id}Get document detail
Get document metadata by id. document-engine internally scopes by RLS on the caller's session.
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Document UUID |
Responses
- 200Document metadata
DocumentDetailResponseField Type Required Description documentDocumentRecordrequired — - 400Validation error
DocumentValidationErrorResponse - 401Unauthorized
DocumentUnauthorizedResponse - 403Forbidden — missing required scope
DocumentUnauthorizedResponse - 404Document not found
DocumentNotFoundResponse - 429Rate limit exceeded
DocumentRateLimitResponse - 500Server error
DocumentUnauthorizedResponse
DELETE/api/documents/{id}Soft-delete document
Soft-delete a document with an optional reason. Returns 204 No Content on success. Already-deleted documents return 409 Conflict.
notices.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Document UUID |
Request body DocumentDeleteBody
| Field | Type | Required | Description |
|---|---|---|---|
reason | string | optional | — |
Responses
- 204Soft-deleted
- 400Validation error
DocumentValidationErrorResponse - 401Unauthorized
DocumentUnauthorizedResponse - 403Forbidden — missing required scope
DocumentUnauthorizedResponse - 404Document not found / not accessible
DocumentNotFoundResponse - 409Document already deleted
DocumentValidationErrorResponse - 429Rate limit exceeded
DocumentRateLimitResponse - 500Server error
DocumentUnauthorizedResponse
POST/api/documents/request-emailSend document-request email
Send a document-request email to an employer contact via Resend. Sender is the caller's display_name + tenant name.
notices.writeRequest body DocumentRequestEmailBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
entity_id | string · uuid | required | — |
recipient_email | string · email | required | — |
recipient_name | string | optional | — |
Responses
- 200Email sent
DocumentRequestEmailResponseField Type Required Description sentenum: truerequired — tostringrequired — - 400Validation error
DocumentValidationErrorResponse - 401Unauthorized
DocumentUnauthorizedResponse - 403Forbidden — missing required scope
DocumentUnauthorizedResponse - 404Entity not found in caller's tenant
DocumentNotFoundResponse - 429Rate limit exceeded
DocumentRateLimitResponse - 500Server error / Resend API failure
DocumentUnauthorizedResponse - 503Email service not configured
DocumentUnauthorizedResponse
POST/api/documents/uploadUpload document
Upload a document (multipart/form-data) for an entity, optionally tied to a document_request. Idempotency-aware (x-idempotency-key header). Tags accept JSON array or comma-separated form.
notices.writeRequest body DocumentUploadMultipartBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
file | string | required | Document binary |
entityId | string · uuid | optional | — |
requestId | string · uuid | optional | — |
tags | string | optional | JSON array or comma-separated tags |
Responses
- 200Uploaded
DocumentUploadResponseField Type Required Description successenum: truerequired — documentDocumentRecordrequired — - 400Validation error
DocumentValidationErrorResponse - 401Unauthorized
DocumentUnauthorizedResponse - 403Forbidden — missing required scope
DocumentUnauthorizedResponse - 404Entity or request not found
DocumentNotFoundResponse - 409Document already exists
DocumentValidationErrorResponse - 429Rate limit exceeded (uploads use the 10/min ceiling)
DocumentRateLimitResponse - 500Server error
DocumentUnauthorizedResponse
POST/api/documents/create-signing-requestCreate signing request link
Create a token-based signature request for a document and return a secure signing link suitable for email delivery. Token expires after 1-30 days.
notices.writeRequest body DocumentCreateSigningRequestBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
document_id | string · uuid | required | — |
entity_id | string · uuid | optional | — |
signer_name | string | required | — |
signer_email | string · email | required | — |
signer_title | string | optional | — |
expires_days | integer | optional | — |
Responses
- 201Signing request created
DocumentCreateSigningRequestResponseField Type Required Description request_idstring · uuidrequired — secure_tokenstring · uuidrequired — signing_linkstringrequired — expires_atstring · date-timerequired — - 400Validation error
DocumentValidationErrorResponse - 401Unauthorized
DocumentUnauthorizedResponse - 403Forbidden — missing required scope
DocumentUnauthorizedResponse - 404Document not found in caller's tenant
DocumentNotFoundResponse - 429Rate limit exceeded
DocumentRateLimitResponse - 500Server error
DocumentUnauthorizedResponse
POST/api/documents/verifyVerify document via AI
Run AI-based document verification on an uploaded file (PDF/PNG/JPG/DOCX, ≤10 MB). Two audit events recorded (requested + completed). Returns documentType + confidence + verified + flags.
notices.writeRequest body DocumentVerifyMultipartBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
file | string | required | PDF/PNG/JPG/DOCX binary (max 10 MB) |
expectedType | string | optional | — |
Responses
- 200Verification result
DocumentVerifyResultField Type Required Description okenum: truerequired — resultobjectrequired — - 400Validation error / unsupported MIME / unreadable file
DocumentValidationErrorResponse - 401Unauthorized
DocumentUnauthorizedResponse - 403Forbidden — missing required scope
DocumentUnauthorizedResponse - 413File too large (>10 MB)
DocumentValidationErrorResponse - 429Rate limit exceeded
DocumentRateLimitResponse - 500Server error / verification pipeline failure
DocumentUnauthorizedResponse
POST/api/check-duplicateCheck upload duplicate
Check if an uploaded file with the given SHA-256 content hash already exists in the caller's tenant (KRT-203). Returns the original upload ID + filename if found. Cookie sessions go through rate-limit middleware.
notices.readRequest body CheckDuplicateBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
contentHash | string | required | — |
Responses
- 200Duplicate check result
CheckDuplicateResponseField Type Required Description isDuplicatebooleanrequired — originalUploadIdstring · uuidoptional — originalFileNamestringoptional — uploadedAtstring · date-timeoptional — - 400Validation error
MiscValidationErrorResponse - 401Unauthorized
MiscUnauthorizedResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
Employer2
GET/api/employer/complianceEmployer compliance items
Employer-portal compliance items (per-state requirements + status). Bearer keys gate via `notices.read`.
notices.readResponses
- 200Compliance items
EmployerComplianceListResponseField Type Required Description itemsarray<EmployerComplianceItem>required — - 401Unauthorized
MiscUnauthorizedResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
GET/api/employer/poaEmployer POA authorizations
Employer-portal POA authorizations per state. Bearer keys gate via `notices.read`.
notices.readResponses
- 200POA items
EmployerPOAListResponseField Type Required Description itemsarray<EmployerPOAItem>required — - 401Unauthorized
MiscUnauthorizedResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
Employers8
POST/api/employersCreate employer
Create a new employer entity for the authenticated CPA's tenant. Validates the body against the multi-axis Zod schema (legal_form, engagement_type, payroll_provider). Returns 201 Created with the new entity ID + legal_name.
Request body CreateEmployerBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
legal_name | string | required | — |
ein_last4 | string | optional | — |
primary_state | string | optional | — |
address | string | optional | — |
city | string | optional | — |
state | string | optional | — |
zip | string | optional | — |
contact_name | string | optional | — |
contact_email | string · email | optional | — |
contact_phone | string | optional | — |
employee_count | integer | optional | — |
legal_form | enum: "llc" | "s_corp" | "sole_prop" | "partnership" | … | optional | — |
engagement_type | enum: "full_managed" | "selective" | "employer_direct" | optional | — |
payroll_provider | enum: "adp" | "gusto" | "paychex" | "manual" | … | optional | — |
Responses
- 201Employer created
CreateEmployerResponseField Type Required Description entityEntitySummaryrequired — - 400Validation error
ValidationErrorResponse - 401Unauthorized
UnauthorizedResponse
PATCH/api/employersUpdate employer
Update an entity's contact info or core identifiers. Tenant-scoped via explicit tenant_id filter (KRT-1191 audit fix).
Request body PatchEmployerBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
entity_id | string · uuid | required | — |
contact_name | string | optional | — |
contact_email | string · email | optional | — |
contact_phone | string | optional | — |
legal_name | string | optional | — |
ein_last4 | string | optional | — |
primary_state | string | optional | — |
Responses
- 200Employer updated
PatchEmployerResponseField Type Required Description entityobjectrequired — - 400Validation error / no fields to update
ValidationErrorResponse - 401Unauthorized
UnauthorizedResponse - 404Entity not found in caller's tenant
NotFoundResponse
GET/api/employers/listList employers
List employers visible to the caller (RLS + explicit tenant filter). Each row carries notice_count, active_notices_count, overdue_notices_count, states_operated, and POA progress. Bearer-key callers need the `employers.read` scope (or NULL for full tenant scope).
employers.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
include_deleted | query | enum: "true" | "false" | optional | When `true`, include soft-deleted entities (CPA-class roles only). |
Responses
- 200Employer list
EmployerListResponseField Type Required Description entitiesarray<EmployerListItem>required — - 401Unauthorized
UnauthorizedResponse - 403Forbidden — missing required scope
UnauthorizedResponse - 429Rate limit exceeded
RateLimitResponse
GET/api/employers/{id}/detailGet employer detail
Return the full entity row with associated notices, POA records, and a derived I-9 compliance summary. All Supabase queries filter by tenant_id explicitly (KRT-1479 P4a Senior-Dev-Override fix).
employers.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Employer entity UUID |
Responses
- 200Employer detail
EmployerDetailResponseField Type Required Description idstring · uuidrequired — tenant_idstring · uuidrequired — legal_namestringrequired — ein_last4stringrequired — primary_statestringrequired — compliance_scorenumberrequired — entity_typestringrequired — contact_namestringrequired — contact_emailstringrequired — contact_phonestringrequired — created_atstring · date-timerequired — is_deletedbooleanoptional — deletion_datestring · date-timeoptional — noticesarray<NoticeSummary>required — poa_recordsarray<PoaRecord>required — i9_compliancearray<I9ComplianceEntry>required — penalties_ytdnumberrequired — - 400Validation error
ValidationErrorResponse - 401Unauthorized
UnauthorizedResponse - 403Forbidden — missing required scope
UnauthorizedResponse - 404Entity not found in caller's tenant
NotFoundResponse - 429Rate limit exceeded
RateLimitResponse
POST/api/employers/update-einUpdate employer EIN
Set the last 4 digits of an entity's EIN, optionally update legal_name, and clear `needs_ein` flag on a referenced notice. Tenant-scoped.
employers.writeRequest body UpdateEinBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
entity_id | string · uuid | required | — |
ein_last4 | string | optional | — |
legal_name | string | optional | — |
notice_id | string · uuid | optional | — |
Responses
- 200Updated
SuccessResponseField Type Required Description successenum: truerequired — - 400Validation error
ValidationErrorResponse - 401Unauthorized
UnauthorizedResponse - 404Entity not found in caller's tenant
NotFoundResponse
PATCH/api/employers/{id}/email-slugCustomize employer notice email
One-time customization of an entity's notice email slug. Once set, the slug is locked (`email_slug_customized=true`) and further changes require operator intervention.
employers.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Employer entity UUID |
Request body EmailSlugBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
slug | string | required | — |
Responses
- 200Slug set
EmailSlugResponseField Type Required Description successenum: truerequired — emailstringrequired — - 400Invalid slug format / already customized
ValidationErrorResponse - 401Unauthorized
UnauthorizedResponse - 404Entity not found in caller's tenant
NotFoundResponse - 409Slug taken by another entity
ValidationErrorResponse
POST/api/employers/{id}/deleteUndo employer soft-delete
Undo a soft-delete. Clears `deleted_at` + `deletion_scheduled_at`. Must be called within the 30-day grace window before /api/employers/cleanup permanently removes the entity row + cascade dependents.
employers.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Employer entity UUID |
Responses
- 200Deletion cancelled
UndoDeleteResponseField Type Required Description successenum: truerequired — entity_idstring · uuidrequired — - 400Entity is not deleted
ValidationErrorResponse - 401Unauthorized
UnauthorizedResponse - 404Entity not found in caller's tenant
NotFoundResponse
DELETE/api/employers/{id}/deleteSoft-delete employer
Soft-delete an entity. Sets `deleted_at` + `deletion_scheduled_at` (now + 30 days). Permanent deletion is run by /api/employers/cleanup (internal cron). Reversible via POST to the same endpoint within the grace window.
employers.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Employer entity UUID |
Responses
- 200Deletion scheduled
DeleteEmployerResponseField Type Required Description successenum: truerequired — scheduled_permanent_deletionstring · date-timerequired — - 401Unauthorized
UnauthorizedResponse - 404Entity not found in caller's tenant
NotFoundResponse - 409Entity already scheduled for deletion
ValidationErrorResponse
Garnishments2
GET/api/garnishmentsList garnishment orders
List garnishment orders for the caller's tenant (compliance category #6 — wage garnishments). client_user is entity-scoped on cookie sessions; Bearer keys see full tenant scope.
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
entity_id | query | string · uuid | optional | — |
status | query | string | optional | — |
order_type | query | string | optional | — |
limit | query | integer | optional | — |
offset | query | integer | optional | — |
Responses
- 200Garnishments
GarnishmentsListResponseField Type Required Description garnishmentsarray<GarnishmentOrder>required — totalintegerrequired — - 401Unauthorized
MiscUnauthorizedResponse - 403Forbidden — entity access denied (client_user scope)
MiscUnauthorizedResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
POST/api/garnishmentsCreate garnishment order
Create a garnishment order. Bearer keys gate via `notices.write`. client_user is entity-scoped on cookie sessions.
notices.writeRequest body GarnishmentCreateBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
entity_id | string · uuid | required | — |
notice_id | string · uuid | optional | — |
order_type | string | optional | — |
court_order_number | string | optional | — |
case_number | string | optional | — |
issuing_authority | string | optional | — |
employee_identifier | string | optional | — |
employee_count | integer | optional | — |
garnishment_amount | number | optional | — |
withholding_percentage | number | optional | — |
max_cumulative | number | optional | — |
priority_order | integer | optional | — |
effective_date | string | optional | — |
expiration_date | string | optional | — |
response_deadline | string | optional | — |
Responses
- 201Garnishment created
GarnishmentCreateResponseField Type Required Description garnishmentGarnishmentOrderrequired — - 400Validation error
MiscValidationErrorResponse - 401Unauthorized
MiscUnauthorizedResponse - 403Forbidden — entity access denied
MiscUnauthorizedResponse - 404Entity not found in caller's tenant
MiscNotFoundResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
I-911
POST/api/i9-compliance/uploadUpload I-9 document
Upload an I-9 document for an employee. Employer-only on cookie sessions; Bearer keys gate via `notices.write`. Multipart body with `file` and `employee_id` fields.
notices.writeRequest body objectrequired
| Field | Type | Required | Description |
|---|---|---|---|
file | string · binary | required | — |
employee_id | string | required | — |
Responses
- 200Uploaded
I9UploadResponseField Type Required Description successenum: truerequired — storage_pathstringrequired — employee_idstringrequired — filenamestringrequired — - 400Validation error
I9ValidationErrorResponse - 401Unauthorized
I9UnauthorizedResponse - 403Forbidden — employer access required / missing scope
I9UnauthorizedResponse - 429Rate limit exceeded
I9RateLimitResponse - 500Server error
I9UnauthorizedResponse
POST/api/i9-compliance/forms/{id}/documentsUpload Section 2 supporting document
Upload a Section 2 supporting document for an I-9 record. CPA-class roles only on cookie sessions; Bearer keys gate via `notices.write`. Multipart body with `file`, `list` (a|b|c), and `index` (0..10).
notices.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | I-9 record UUID |
Request body objectrequired
| Field | Type | Required | Description |
|---|---|---|---|
file | string · binary | required | — |
list | enum: "a" | "b" | "c" | required | — |
index | integer | required | — |
Responses
- 201Document uploaded
I9RecordResponseField Type Required Description recordI9Recordrequired — - 400Validation error
I9ValidationErrorResponse - 401Unauthorized
I9UnauthorizedResponse - 403Forbidden — CPA access required
I9UnauthorizedResponse - 404I-9 record not found
I9NotFoundResponse - 429Rate limit exceeded
I9RateLimitResponse - 500Server error
I9UnauthorizedResponse
GET/api/i9-compliance/forms/{id}/pdfDownload I-9 PDF
Render the I-9 record as a flattened PDF. CPA-class roles only on cookie sessions; Bearer keys gate via `notices.read`.
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | I-9 record UUID |
Responses
- 200PDF binary
I9PdfBinaryResponse - 401Unauthorized
I9UnauthorizedResponse - 403Forbidden — CPA access required
I9UnauthorizedResponse - 404I-9 record not found
I9NotFoundResponse - 429Rate limit exceeded
I9RateLimitResponse - 500Server error
I9UnauthorizedResponse
GET/api/i9-compliance/forms/{id}Get I-9 record
Get a single I-9 record. CPA-class roles only on cookie sessions; Bearer keys gate via `notices.read`.
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | I-9 record UUID |
Responses
- 200I-9 record
I9RecordResponseField Type Required Description recordI9Recordrequired — - 400Validation error
I9ValidationErrorResponse - 401Unauthorized
I9UnauthorizedResponse - 403Forbidden — CPA access required
I9UnauthorizedResponse - 404I-9 record not found
I9NotFoundResponse - 429Rate limit exceeded
I9RateLimitResponse - 500Server error
I9UnauthorizedResponse
PATCH/api/i9-compliance/forms/{id}Update I-9 Section 2
Update an I-9 record's Section 2 data (employer review). Validates List A is mutually exclusive with List B/C. CPA-class roles only on cookie sessions; Bearer keys gate via `notices.write`.
notices.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | I-9 record UUID |
Request body I9Section2Bodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
list_a_docs | array<I9DocumentEntry> | optional | — |
list_b_docs | array<I9DocumentEntry> | optional | — |
list_c_docs | array<I9DocumentEntry> | optional | — |
reviewer_name | string | required | — |
reviewer_title | string | required | — |
date_of_hire | string | required | — |
date_of_completion | string | required | — |
Responses
- 200I-9 record updated
I9RecordResponseField Type Required Description recordI9Recordrequired — - 400Validation error / invalid document combination
I9ValidationErrorResponse - 401Unauthorized
I9UnauthorizedResponse - 403Forbidden — CPA access required
I9UnauthorizedResponse - 404I-9 record not found
I9NotFoundResponse - 409Section 1 must be completed first
I9ValidationErrorResponse - 429Rate limit exceeded
I9RateLimitResponse - 500Server error
I9UnauthorizedResponse
GET/api/i9-compliance/formsList I-9 records by employee
List I-9 records for a given employee. CPA-class roles only on cookie sessions; Bearer keys gate via `notices.read`.
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
employee_id | query | string · uuid | required | — |
Responses
- 200I-9 records
I9RecordsListResponseField Type Required Description recordsarray<I9Record>required — - 400Validation error
I9ValidationErrorResponse - 401Unauthorized
I9UnauthorizedResponse - 403Forbidden — CPA access required
I9UnauthorizedResponse - 429Rate limit exceeded
I9RateLimitResponse - 500Server error
I9UnauthorizedResponse
POST/api/i9-compliance/formsCreate I-9 record (Section 1)
Create an I-9 record (Section 1). Cross-field validation: LPR requires alien_registration_number; authorized_alien requires at least one of A-Number / I-94 / passport+country. CPA-class roles only on cookie sessions; Bearer keys gate via `notices.write`.
notices.writeRequest body I9Section1CreateBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
employee_id | string · uuid | required | — |
citizenship_status | I9CitizenshipStatus | required | — |
section1_data | I9Section1Data | required | — |
ssn | string | optional | — |
Responses
- 201I-9 record created
I9RecordResponseField Type Required Description recordI9Recordrequired — - 400Validation error
I9ValidationErrorResponse - 401Unauthorized
I9UnauthorizedResponse - 403Forbidden — CPA access required
I9UnauthorizedResponse - 429Rate limit exceeded
I9RateLimitResponse - 500Server error
I9UnauthorizedResponse
GET/api/i9-compliance/{employeeId}Get employee I-9 detail
Get a single employee's I-9 details + uploaded documents. Falls back to payroll_pay_periods when employeeId is an SSN hash. cookie sessions: client_user is entity-scoped; CPA roles see all. Bearer keys gate via `notices.read` (full tenant access).
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
employeeId | path | string | required | Employee UUID or SSN hash |
Responses
- 200Employee + documents
I9EmployeeDetailResponseField Type Required Description employeeI9EmployeeI9required — documentsarray<I9DocumentRow>required — sourceenum: "employees" | "payroll_pay_periods"required — - 401Unauthorized
I9UnauthorizedResponse - 403Not authorized for this employee (entity-scope check)
I9UnauthorizedResponse - 404Employee not found
I9NotFoundResponse - 429Rate limit exceeded
I9RateLimitResponse - 500Server error
I9UnauthorizedResponse
POST/api/i9-compliance/bulk-uploadBulk upload + match I-9 documents
Bulk upload up to 50 I-9 documents. Extracts employee names from filenames and fuzzy-matches against the active roster (entity-scoped for client_user; full tenant for CPA / Bearer keys with `notices.write`). Returns matched + unmatched results — does not persist files.
notices.writeRequest body objectrequired
| Field | Type | Required | Description |
|---|---|---|---|
files | array<string · binary> | required | — |
Responses
- 200Match results
I9BulkUploadResponseField Type Required Description totalintegerrequired — matchedarray<I9BulkMatch>required — unmatchedarray<I9BulkUnmatched>required — - 400Validation error
I9ValidationErrorResponse - 401Unauthorized
I9UnauthorizedResponse - 429Rate limit exceeded
I9RateLimitResponse - 500Server error
I9UnauthorizedResponse
GET/api/i9-complianceList I-9 employees
List I-9 employee records for the caller's tenant + expiry stats. Falls back to payroll_pay_periods when no employees rows exist. Bearer keys gate via `notices.read`.
notices.readResponses
- 200Employee list + expiry stats
I9EmployeesListResponseField Type Required Description employeesarray<I9EmployeeListItem>required — expiry_statsobjectoptional — sourcestringoptional — messagestringoptional — - 401Unauthorized
I9UnauthorizedResponse - 429Rate limit exceeded
I9RateLimitResponse - 500Server error
I9UnauthorizedResponse
POST/api/i9-complianceCreate I-9 employee
Create a new I-9 employee record. Employer-only on cookie sessions; Bearer keys gate via `notices.write`.
notices.writeRequest body I9EmployeeCreateBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
employee_name | string | required | — |
hire_date | string | required | — |
entity_id | string · uuid | required | — |
email | string · email | optional | — |
department | string | optional | — |
Responses
- 201Employee created
I9EmployeeCreateResponseField Type Required Description employeeI9EmployeeListItemrequired — - 400Validation error
I9ValidationErrorResponse - 401Unauthorized
I9UnauthorizedResponse - 403Forbidden — employer access required
I9UnauthorizedResponse - 404Entity not found in caller's tenant
I9NotFoundResponse - 429Rate limit exceeded
I9RateLimitResponse - 500Server error
I9UnauthorizedResponse - 501Employees table not provisioned yet
I9UnauthorizedResponse
KnowledgeBase1
GET/api/knowledge-baseQuery state compliance knowledge
Query the global state_compliance_knowledge table — Kreto-wide reference data covering state-by-state compliance rules, notice types, and deadlines. No tenant filter (read-only reference data). Bearer keys gate via `notices.read`.
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
state | query | string | optional | — |
type | query | string | optional | — |
q | query | string | optional | — |
min_confidence | query | number | optional | — |
limit | query | integer | optional | — |
offset | query | integer | optional | — |
Responses
- 200Knowledge entries + summary
KnowledgeBaseResponseField Type Required Description entriesarray<KnowledgeBaseEntry>required — totalintegerrequired — summaryobjectrequired — - 401Unauthorized
MiscUnauthorizedResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
l2:annual-reports12
POST/v1/annual-reports.listAnnualReportRulesList the state annual-report catalog (global config): per-(state, entity_kind) SOS annual/biennial report rules with the verification ladder status of every cell and honest per-status counts. Cells below the display gate (human_reviewed) must never be rendered as authoritative to customers.
List the state annual-report catalog (global config): per-(state, entity_kind) SOS annual/biennial report rules with the verification ladder status of every cell and honest per-status counts. Cells below the display gate (human_reviewed) must never be rendered as authoritative to customers.
Request body AnnualReportsListAnnualReportRulesInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
stateCode | string | optional | — |
entityKind | enum: "corporation" | "llc" | "nonprofit" | "lp" | … | optional | — |
verificationStatus | enum: "unverified" | "human_reviewed" | "verified" | optional | — |
Responses
- 200Successful invocation
AnnualReportsListAnnualReportRulesOutputField Type Required Description rulesarray<object>required — countsobjectrequired — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/annual-reports.getAnnualReportRuleFetch one annual-report catalog cell with the (state, entity_kind) → (state, 'default') fallback. Returns the human-readable due-rule narrative alongside the raw rule. Null rule = no catalog coverage yet.
Fetch one annual-report catalog cell with the (state, entity_kind) → (state, 'default') fallback. Returns the human-readable due-rule narrative alongside the raw rule. Null rule = no catalog coverage yet.
Request body AnnualReportsGetAnnualReportRuleInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
stateCode | string | required | — |
entityKind | enum: "corporation" | "llc" | "nonprofit" | "lp" | … | optional | — |
Responses
- 200Successful invocation
AnnualReportsGetAnnualReportRuleOutputField Type Required Description ruleobjectrequired — usedDefaultFallbackbooleanrequired — dueNarrativestringrequired — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/annual-reports.proposeAnnualReportRuleResearch-agent write path for the annual-report catalog. Upserts one (state, entity_kind) cell as verification_status='unverified' with mandatory provenance (source_url + retrieved_at). REFUSES to touch a cell already at human_reviewed/verified — verified cells are never downgraded (AC-22 clone); corrections go through the review queue.
Research-agent write path for the annual-report catalog. Upserts one (state, entity_kind) cell as verification_status='unverified' with mandatory provenance (source_url + retrieved_at). REFUSES to touch a cell already at human_reviewed/verified — verified cells are never downgraded (AC-22 clone); corrections go through the review queue.
Request body AnnualReportsProposeAnnualReportRuleInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
stateCode | string | required | — |
entityKind | enum: "corporation" | "llc" | "nonprofit" | "lp" | … | optional | — |
agencyCode | string | required | — |
agencyName | string | required | — |
portalUrl | string · uri | optional | — |
formName | string | optional | — |
filingFeeUsd | number | optional | — |
frequency | enum: "annual" | "biennial" | "decennial" | "none" | required | — |
dueRule | one of (object · object · object · object · object) | required | — |
parity | enum: "odd" | "even" | "formation_year" | optional | — |
gracePeriodDays | integer | optional | — |
lateFeeNotes | string | optional | — |
sourceUrl | string · uri | required | — |
retrievedAt | string · date-time | required | — |
notes | string | optional | — |
Responses
- 200Successful invocation
AnnualReportsProposeAnnualReportRuleOutputField Type Required Description ruleobjectrequired — createdbooleanrequired — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/annual-reports.promoteAnnualReportRulePromote an annual-report catalog cell along the verification ladder (unverified → human_reviewed → verified). APPROVAL_REQUIRED and UI-only: the handler rejects any non-human principal (AC-20 clone) and refuses cells with no source_url provenance (CWE-345).
Promote an annual-report catalog cell along the verification ladder (unverified → human_reviewed → verified). APPROVAL_REQUIRED and UI-only: the handler rejects any non-human principal (AC-20 clone) and refuses cells with no source_url provenance (CWE-345).
Request body AnnualReportsPromoteAnnualReportRuleInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
stateCode | string | required | — |
entityKind | enum: "corporation" | "llc" | "nonprofit" | "lp" | … | optional | — |
targetStatus | enum: "human_reviewed" | "verified" | required | — |
reviewerEmail | string · email | required | — |
reason | string | required | — |
Responses
- 200Successful invocation
AnnualReportsPromoteAnnualReportRuleOutputField Type Required Description ruleobjectrequired — fromStatusenum: "unverified" | "human_reviewed" | "verified"required — toStatusenum: "unverified" | "human_reviewed" | "verified"required — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/annual-reports.listAnnualReportsList the tenant's annual-report tracker rows (per entity × state × filing period), filterable by entity, state, status and period. Paginated (default 25). Tenant-scoped via the invocation context.
List the tenant's annual-report tracker rows (per entity × state × filing period), filterable by entity, state, status and period. Paginated (default 25). Tenant-scoped via the invocation context.
Request body AnnualReportsListAnnualReportsInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
entityId | string | optional | — |
stateCode | string | optional | — |
status | enum: "pending" | "prepared" | "submitted" | "approved" | … | optional | — |
periodLabel | string | optional | — |
limit | integer | optional | — |
offset | integer | optional | — |
Responses
- 200Successful invocation
AnnualReportsListAnnualReportsOutputField Type Required Description reportsarray<object>required — totalnumberrequired — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/annual-reports.getAnnualReportByEntityFetch every annual-report tracker row for one entity (optionally one state), all periods — history plus in-flight. Tenant-scoped.
Fetch every annual-report tracker row for one entity (optionally one state), all periods — history plus in-flight. Tenant-scoped.
Request body AnnualReportsGetAnnualReportByEntityInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
entityId | string | required | — |
stateCode | string | optional | — |
Responses
- 200Successful invocation
AnnualReportsGetAnnualReportByEntityOutputField Type Required Description reportsarray<object>required — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/annual-reports.computeAnnualReportScheduleDry-run compute of an entity's annual-report schedule for one period year (default: current year): per candidate state, the computed due date OR an explicit non-computed disposition (needs_input / needs_research / below_display_gate / not_required / not_due_this_period). Writes nothing — the sweep's cycle roller persists rows; this method answers 'what would be due?'.
Dry-run compute of an entity's annual-report schedule for one period year (default: current year): per candidate state, the computed due date OR an explicit non-computed disposition (needs_input / needs_research / below_display_gate / not_required / not_due_this_period). Writes nothing — the sweep's cycle roller persists rows; this method answers 'what would be due?'.
Request body AnnualReportsComputeAnnualReportScheduleInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
entityId | string | required | — |
periodYear | integer | optional | — |
Responses
- 200Successful invocation
AnnualReportsComputeAnnualReportScheduleOutputField Type Required Description entityIdstringrequired — periodYearnumberrequired — itemsarray<object>required — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/annual-reports.createAnnualReportCreate one manual annual-report tracker row (source='manual') for an entity × state × period. Computes the due date from the display-gated catalog when possible; otherwise the row starts manual_required with a NULL due date ('Kreto needs your input'). Duplicate periods are rejected by the per-period UNIQUE.
Create one manual annual-report tracker row (source='manual') for an entity × state × period. Computes the due date from the display-gated catalog when possible; otherwise the row starts manual_required with a NULL due date ('Kreto needs your input'). Duplicate periods are rejected by the per-period UNIQUE.
Request body AnnualReportsCreateAnnualReportInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
entityId | string | required | — |
stateCode | string | required | — |
periodLabel | string | required | — |
anchorKind | enum: "formation" | "foreign_qualification" | "manual" | optional | — |
anchorDate | string | optional | — |
notes | string | optional | — |
Responses
- 200Successful invocation
AnnualReportsCreateAnnualReportOutputField Type Required Description reportobjectrequired — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/annual-reports.updateAnnualReportMetadataEdit tracker metadata on one annual-report row: anchor date/kind (recomputes the due date from the display-gated catalog and flips manual_required → pending when a date becomes computable), assignee and notes. Writes a structured audit event capturing before/after.
Edit tracker metadata on one annual-report row: anchor date/kind (recomputes the due date from the display-gated catalog and flips manual_required → pending when a date becomes computable), assignee and notes. Writes a structured audit event capturing before/after.
Request body AnnualReportsUpdateAnnualReportMetadataInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
annualReportId | string | required | — |
anchorDate | string | optional | — |
anchorKind | enum: "formation" | "foreign_qualification" | "manual" | optional | — |
assignee | string | optional | — |
notes | string | optional | — |
reason | string | required | — |
Responses
- 200Successful invocation
AnnualReportsUpdateAnnualReportMetadataOutputField Type Required Description reportobjectrequired — changedFieldsarray<string>required — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/annual-reports.prepareAnnualReportPopulate an annual report's prepared form payload (officers, principal address, the customer's OWN registered agent — Kreto is not the RA) and transition pending/manual_required → prepared. APPROVAL_REQUIRED: symmetric with prepareRegistrationForm; a human reviews before any filing. PII in form_payload is scrubbed from audit rows.
Populate an annual report's prepared form payload (officers, principal address, the customer's OWN registered agent — Kreto is not the RA) and transition pending/manual_required → prepared. APPROVAL_REQUIRED: symmetric with prepareRegistrationForm; a human reviews before any filing. PII in form_payload is scrubbed from audit rows.
Request body AnnualReportsPrepareAnnualReportInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
annualReportId | string | required | — |
formPayload | object | required | — |
Responses
- 200Successful invocation
AnnualReportsPrepareAnnualReportOutputField Type Required Description reportobjectrequired — fromStatusenum: "pending" | "prepared" | "submitted" | "approved" | …required — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/annual-reports.requestConciergeFilingRecord the '$149 File it for me' concierge request on a prepared annual report: stamps filing_requested_at/by (design D3 — an annotation on 'prepared', not a status) and charges the $149 as a standalone Stripe invoice (created + finalized, so it bills every customer; owner 2026-07-10; fail-closed when STRIPE_SECRET_KEY is unset; double-bill safe). APPROVAL_REQUIRED: this moves money, so the v1 dispatcher blocks non-interactive API-key / MCP callers (KRT-1657) — it requires an interactive human session. The click by an authenticated CPA/owner IS the recorded filing authorization. The state filing fee is separate and paid to the state.
Record the '$149 File it for me' concierge request on a prepared annual report: stamps filing_requested_at/by (design D3 — an annotation on 'prepared', not a status) and charges the $149 as a standalone Stripe invoice (created + finalized, so it bills every customer; owner 2026-07-10; fail-closed when STRIPE_SECRET_KEY is unset; double-bill safe). APPROVAL_REQUIRED: this moves money, so the v1 dispatcher blocks non-interactive API-key / MCP callers (KRT-1657) — it requires an interactive human session. The click by an authenticated CPA/owner IS the recorded filing authorization. The state filing fee is separate and paid to the state.
Request body AnnualReportsRequestConciergeFilingInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
annualReportId | string | required | — |
Responses
- 200Successful invocation
AnnualReportsRequestConciergeFilingOutputField Type Required Description reportobjectrequired — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/annual-reports.transitionAnnualReportStatusApply a matrix-gated status transition to an annual-report tracker row (exact esr 7-status machine). Supports the mark-filed extras (confirmationNumber + filedAt on → submitted) and the confirmedImmediately chain (submitted → approved in one audited call for instant-confirm states). Every hop writes a hash-chained audit_events row.
Apply a matrix-gated status transition to an annual-report tracker row (exact esr 7-status machine). Supports the mark-filed extras (confirmationNumber + filedAt on → submitted) and the confirmedImmediately chain (submitted → approved in one audited call for instant-confirm states). Every hop writes a hash-chained audit_events row.
Request body AnnualReportsTransitionAnnualReportStatusInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
annualReportId | string | required | — |
newStatus | enum: "pending" | "prepared" | "submitted" | "approved" | … | required | — |
reason | string | required | — |
confirmationNumber | string | optional | — |
filedAt | string · date-time | optional | — |
confirmedImmediately | boolean | optional | — |
lastError | string | optional | — |
Responses
- 200Successful invocation
AnnualReportsTransitionAnnualReportStatusOutputField Type Required Description reportobjectrequired — fromStatusenum: "pending" | "prepared" | "submitted" | "approved" | …required — toStatusenum: "pending" | "prepared" | "submitted" | "approved" | …required — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
l2:audit1
POST/v1/audit.getRecentForRegistrationReturn recent service_audit_log rows linked to a specific state_registration row (via linked_resource_ids.registrationId). Tenant-scoped. AUTONOMOUS: append-only audit-table reads have no side effects.
Return recent service_audit_log rows linked to a specific state_registration row (via linked_resource_ids.registrationId). Tenant-scoped. AUTONOMOUS: append-only audit-table reads have no side effects.
Request body AuditGetRecentForRegistrationInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
registrationId | string | required | — |
limit | integer | optional | — |
Responses
- 200Successful invocation
AuditGetRecentForRegistrationOutputField Type Required Description eventsarray<object>required — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
l2:business-license5
POST/v1/business-license.listLicensesList the business licenses and local permits tracked for the tenant (optionally filtered to one entity), soft-deleted rows excluded, ordered by soonest expiration. Read-only. Kreto tracks licenses the employer already holds — it does not discover, obtain, or renew them.
List the business licenses and local permits tracked for the tenant (optionally filtered to one entity), soft-deleted rows excluded, ordered by soonest expiration. Read-only. Kreto tracks licenses the employer already holds — it does not discover, obtain, or renew them.
Request body BusinessLicenseListLicensesInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
entityId | string · uuid | optional | — |
Responses
- 200Successful invocation
BusinessLicenseListLicensesOutputField Type Required Description licensesarray<object>required — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/business-license.createLicenseRecord a business license or local permit the employer already holds (manual tracker entry). Verifies the target entity belongs to the caller's tenant, inserts the row, and appends a hash-chained business_license.created audit event. NOTIFY classification: agents can call but the action is logged for human review.
Record a business license or local permit the employer already holds (manual tracker entry). Verifies the target entity belongs to the caller's tenant, inserts the row, and appends a hash-chained business_license.created audit event. NOTIFY classification: agents can call but the action is logged for human review.
Request body BusinessLicenseCreateLicenseInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
entityId | string · uuid | required | — |
licenseName | string | required | — |
licenseType | enum: "state_business" | "city_business" | "county_business" | "professional" | … | required | — |
licenseNumber | string | optional | — |
issuingAuthority | string | required | — |
state | string | optional | — |
jurisdiction | string | optional | — |
status | enum: "active" | "expired" | "pending" | "suspended" | … | optional | — |
issuedDate | string | optional | — |
expirationDate | string | optional | — |
renewalDate | string | optional | — |
renewalFee | number | optional | — |
autoRenew | boolean | optional | — |
notes | string | optional | — |
Responses
- 200Successful invocation
BusinessLicenseCreateLicenseOutputField Type Required Description licenseobjectrequired — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/business-license.updateLicenseEdit a tracked business license. Absent key = unchanged, null = clear (where the column is nullable). Appends a hash-chained business_license.updated audit event carrying per-field old → new. No-op submits write nothing. NOTIFY classification: agents can call but the action is logged for human review.
Edit a tracked business license. Absent key = unchanged, null = clear (where the column is nullable). Appends a hash-chained business_license.updated audit event carrying per-field old → new. No-op submits write nothing. NOTIFY classification: agents can call but the action is logged for human review.
Request body BusinessLicenseUpdateLicenseInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
licenseId | string · uuid | required | — |
licenseName | string | optional | — |
licenseType | enum: "state_business" | "city_business" | "county_business" | "professional" | … | optional | — |
licenseNumber | string | optional | — |
issuingAuthority | string | optional | — |
state | string | optional | — |
jurisdiction | string | optional | — |
status | enum: "active" | "expired" | "pending" | "suspended" | … | optional | — |
issuedDate | string | optional | — |
expirationDate | string | optional | — |
renewalDate | string | optional | — |
renewalFee | number | optional | — |
autoRenew | boolean | optional | — |
notes | string | optional | — |
Responses
- 200Successful invocation
BusinessLicenseUpdateLicenseOutputField Type Required Description licenseobjectrequired — changedFieldsarray<string>required — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/business-license.recordRenewalRecord a license renewal the employer/CPA already completed with the issuing authority: moves the license's expiration date, recomputes status, and appends a license_renewal_history row plus a hash-chained business_license.renewed audit event. Kreto never performs the renewal itself. NOTIFY classification: agents can call but the action is logged for human review.
Record a license renewal the employer/CPA already completed with the issuing authority: moves the license's expiration date, recomputes status, and appends a license_renewal_history row plus a hash-chained business_license.renewed audit event. Kreto never performs the renewal itself. NOTIFY classification: agents can call but the action is logged for human review.
Request body BusinessLicenseRecordRenewalInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
licenseId | string · uuid | required | — |
newExpirationDate | string | required | — |
renewalCost | number | optional | — |
confirmationNumber | string | optional | — |
notes | string | optional | — |
Responses
- 200Successful invocation
BusinessLicenseRecordRenewalOutputField Type Required Description licenseobjectrequired — historyRecordedbooleanrequired — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/business-license.deleteLicenseSoft-delete a tracked business license (sets deleted_at; the row stays for audit). Pending renewal-alert idempotency rows CASCADE on hard delete only — soft-deleted rows simply stop matching the reminder scan. Appends a hash-chained business_license.deleted audit event. NOTIFY classification: agents can call but the action is logged for human review.
Soft-delete a tracked business license (sets deleted_at; the row stays for audit). Pending renewal-alert idempotency rows CASCADE on hard delete only — soft-deleted rows simply stop matching the reminder scan. Appends a hash-chained business_license.deleted audit event. NOTIFY classification: agents can call but the action is logged for human review.
Request body BusinessLicenseDeleteLicenseInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
licenseId | string · uuid | required | — |
Responses
- 200Successful invocation
BusinessLicenseDeleteLicenseOutputField Type Required Description licenseIdstringrequired — deletedAtstringrequired — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
l2:consent2
POST/v1/consent.captureRecord the one-time blanket account-level consent that authorizes Kreto to store and use this account's portal credentials, with money movement explicitly enumerated (every payment still requires its own human approval — a hard floor). Idempotent: returns the existing active grant instead of duplicating.
Record the one-time blanket account-level consent that authorizes Kreto to store and use this account's portal credentials, with money movement explicitly enumerated (every payment still requires its own human approval — a hard floor). Idempotent: returns the existing active grant instead of duplicating.
Request body ConsentCaptureInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
acknowledged | enum: true | required | — |
Responses
- 200Successful invocation
ConsentCaptureOutputField Type Required Description grantobjectrequired — isNewGrantbooleanrequired — textVersionstringrequired — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/consent.getRead the account's active blanket vault-consent grant (or null) plus the current consent text version. Use before storing a credential to check whether the consent precondition is satisfied.
Read the account's active blanket vault-consent grant (or null) plus the current consent text version. Use before storing a credential to check whether the consent precondition is satisfied.
Request body ConsentGetInputrequired
application/json
Responses
- 200Successful invocation
ConsentGetOutputField Type Required Description grantobjectrequired — textVersionstringrequired — textstringrequired — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
l2:cpa4
POST/v1/cpa.listEmployersList the CPA's linked employers (entities) with per-employer notice counts. Paginated via `limit` (1-100, default 25) and zero-indexed `offset`. Optional case-insensitive `search` filters on legal_name. Tenant-scoped. Returns aggregates only — no PII (no signer info, no employee names, no notice subjects).
List the CPA's linked employers (entities) with per-employer notice counts. Paginated via `limit` (1-100, default 25) and zero-indexed `offset`. Optional case-insensitive `search` filters on legal_name. Tenant-scoped. Returns aggregates only — no PII (no signer info, no employee names, no notice subjects).
Request body CpaListEmployersInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
limit | integer | optional | — |
offset | integer | optional | — |
search | string | optional | — |
Responses
- 200Successful invocation
CpaListEmployersOutputField Type Required Description employersarray<object>required — totalintegerrequired — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/cpa.summarizeComplianceAggregate the CPA tenant's compliance posture: notice counts by status, per-employer rollup, fines (total/paid/outstanding cents), and response-time average. Tenant-scoped. Returns aggregates only — no PII.
Aggregate the CPA tenant's compliance posture: notice counts by status, per-employer rollup, fines (total/paid/outstanding cents), and response-time average. Tenant-scoped. Returns aggregates only — no PII.
Request body CpaSummarizeComplianceInputrequired
application/json
Responses
- 200Successful invocation
CpaSummarizeComplianceOutputField Type Required Description generated_atstringrequired — tenant_idstringrequired — noticesobjectrequired — per_entityarray<object>required — finesobjectrequired — response_timeobjectrequired — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/cpa.queryAuditEventsQuery the tenant's audit event timeline. Paginated via `limit` (1-100, default 25) and zero-indexed `offset`. Optional filters: `entity_id` (UUID), `notice_id` (UUID), `event_type` (exact match e.g. 'notice_created'), `since`/`until` (ISO datetimes). Tenant-scoped. `detail` is PII-redacted (SSN/EIN/bank patterns replaced) and capped at 500 chars. Metadata + integrity-chain columns are NOT returned.
Query the tenant's audit event timeline. Paginated via `limit` (1-100, default 25) and zero-indexed `offset`. Optional filters: `entity_id` (UUID), `notice_id` (UUID), `event_type` (exact match e.g. 'notice_created'), `since`/`until` (ISO datetimes). Tenant-scoped. `detail` is PII-redacted (SSN/EIN/bank patterns replaced) and capped at 500 chars. Metadata + integrity-chain columns are NOT returned.
Request body CpaQueryAuditEventsInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
limit | integer | optional | — |
offset | integer | optional | — |
entity_id | string · uuid | optional | — |
notice_id | string · uuid | optional | — |
event_type | string | optional | — |
since | string · date-time | optional | — |
until | string · date-time | optional | — |
Responses
- 200Successful invocation
CpaQueryAuditEventsOutputField Type Required Description eventsarray<object>required — totalintegerrequired — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/cpa.summarizeObligationsAggregate compliance-obligations rollup across the CPA's employer book. Paginated via `limit` (1-100, default 25) and zero-indexed `offset`; optional case-insensitive `search` on legal_name. For each employer: applicable / low-confidence / pending-data obligation counts plus the earliest computable due date; firm-wide totals included. Tenant-scoped. Returns aggregates only — no PII (no employee data, no wages, no notice subjects).
Aggregate compliance-obligations rollup across the CPA's employer book. Paginated via `limit` (1-100, default 25) and zero-indexed `offset`; optional case-insensitive `search` on legal_name. For each employer: applicable / low-confidence / pending-data obligation counts plus the earliest computable due date; firm-wide totals included. Tenant-scoped. Returns aggregates only — no PII (no employee data, no wages, no notice subjects).
Request body CpaSummarizeObligationsInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
limit | integer | optional | — |
offset | integer | optional | — |
search | string | optional | — |
Responses
- 200Successful invocation
CpaSummarizeObligationsOutputField Type Required Description per_entityarray<object>required — totalsobjectrequired — totalintegerrequired — generated_atstringrequired — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
l2:cpa-team-invitations5
POST/v1/cpa-team-invitations.createInvitationCreate a firm team-invitation row, generate a single-use accept token, and send the invite email. Returns plaintext accept_url ONCE. Only firm_admin/system_admin may call.
Create a firm team-invitation row, generate a single-use accept token, and send the invite email. Returns plaintext accept_url ONCE. Only firm_admin/system_admin may call.
Request body CpaTeamInvitationsCreateInvitationInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
email | string · email | required | — |
invited_role | enum: "cpa_member" | "staff" | required | — |
Responses
- 200Successful invocation
CpaTeamInvitationsCreateInvitationOutputField Type Required Description invitationobjectrequired — accept_urlstring · urirequired — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/cpa-team-invitations.listInvitationsList firm team invitations for the caller's tenant. Never returns plaintext tokens or token hashes.
List firm team invitations for the caller's tenant. Never returns plaintext tokens or token hashes.
Request body CpaTeamInvitationsListInvitationsInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
status | enum: "pending" | "accepted" | "revoked" | "expired" | optional | — |
Responses
- 200Successful invocation
CpaTeamInvitationsListInvitationsOutputField Type Required Description invitationsarray<object>required — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/cpa-team-invitations.revokeInvitationRevoke a pending firm invitation. Idempotent for already-revoked/accepted rows (returns current status). Only firm_admin/system_admin may revoke.
Revoke a pending firm invitation. Idempotent for already-revoked/accepted rows (returns current status). Only firm_admin/system_admin may revoke.
Request body CpaTeamInvitationsRevokeInvitationInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
invitation_id | string · uuid | required | — |
Responses
- 200Successful invocation
CpaTeamInvitationsRevokeInvitationOutputField Type Required Description idstring · uuidrequired — statusstringrequired — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/cpa-team-invitations.acceptInvitationAccept a firm team invitation. Verifies token, expiry, self-acceptance and email-mismatch guards. Grants user_profiles.role + a portal_roles row on success. The caller MUST be signed in as the invited email.
Accept a firm team invitation. Verifies token, expiry, self-acceptance and email-mismatch guards. Grants user_profiles.role + a portal_roles row on success. The caller MUST be signed in as the invited email.
Request body CpaTeamInvitationsAcceptInvitationInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
token | string | required | — |
Responses
- 200Successful invocation
CpaTeamInvitationsAcceptInvitationOutputField Type Required Description invitation_idstring · uuidrequired — invited_rolestringrequired — role_grantedbooleanrequired — existing_role_preservedbooleanrequired — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/cpa-team-invitations.getInvitationByTokenPublic lookup by plaintext token (hashes on read; never returns hash or plaintext). Used by /accept-cpa-invite/[token] for render.
Public lookup by plaintext token (hashes on read; never returns hash or plaintext). Used by /accept-cpa-invite/[token] for render.
Request body CpaTeamInvitationsGetInvitationByTokenInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
token | string | required | — |
Responses
- 200Successful invocation
CpaTeamInvitationsGetInvitationByTokenOutputField Type Required Description invitationobjectrequired — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
l2:credential-vault15
POST/v1/credential-vault.createCredentialCreate a tax account credential. Plaintext password / mfaSecret fields are written to Supabase Vault (vault.secrets) and the returned secret IDs are stored on tax_account_credentials. APPROVAL_REQUIRED — agents must not invoke this without HITL.
Create a tax account credential. Plaintext password / mfaSecret fields are written to Supabase Vault (vault.secrets) and the returned secret IDs are stored on tax_account_credentials. APPROVAL_REQUIRED — agents must not invoke this without HITL.
Request body CredentialVaultCreateCredentialInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
employerEntityId | string | required | — |
agencyId | string | required | — |
accountNumber | string | optional | — |
loginUsername | string | optional | — |
password | string | optional | — |
mfaSecret | string | optional | — |
backupCodes | string | optional | — |
notes | string | optional | — |
otpChannel | enum: "none" | "totp" | "email" | "sms" | optional | — |
Responses
- 200Successful invocation
CredentialVaultCreateCredentialOutputField Type Required Description idstringrequired — tenant_idstringrequired — employer_entity_idstringrequired — agency_idstringrequired — account_numberstringrequired — login_usernamestringrequired — has_passwordbooleanrequired — has_mfa_secretbooleanrequired — has_backup_codesbooleanrequired — last_login_atstringrequired — last_password_change_atstringrequired — refresh_required_bystringrequired — statusenum: "active" | "revoked" | "refresh_required" | "locked"required — notesstringrequired — created_atstringrequired — updated_atstringrequired — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/credential-vault.getCredentialFetch a credential by id, including plaintext password and mfaSecret decrypted from Supabase Vault. APPROVAL_REQUIRED. The returned plaintext fields are named `password` / `mfaSecret` (camelCase, matching framework SENSITIVE_KEYS) so the audit row's outputs JSONB shows them as [redacted] while the live caller receives the actual plaintext (R13 mitigation).
Fetch a credential by id, including plaintext password and mfaSecret decrypted from Supabase Vault. APPROVAL_REQUIRED. The returned plaintext fields are named `password` / `mfaSecret` (camelCase, matching framework SENSITIVE_KEYS) so the audit row's outputs JSONB shows them as [redacted] while the live caller receives the actual plaintext (R13 mitigation).
Request body CredentialVaultGetCredentialInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
credentialId | string | required | — |
purpose | string | required | — |
Responses
- 200Successful invocation
CredentialVaultGetCredentialOutputField Type Required Description idstringrequired — tenant_idstringrequired — employer_entity_idstringrequired — agency_idstringrequired — account_numberstringrequired — login_usernamestringrequired — has_passwordbooleanrequired — has_mfa_secretbooleanrequired — has_backup_codesbooleanrequired — last_login_atstringrequired — last_password_change_atstringrequired — refresh_required_bystringrequired — statusenum: "active" | "revoked" | "refresh_required" | "locked"required — notesstringrequired — created_atstringrequired — updated_atstringrequired — passwordstringrequired — mfaSecretstringrequired — backupCodesstringrequired — health_check_auto_flipbooleanoptional — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/credential-vault.getCredentialByEntityResolve and fetch a credential by (tenantId, entityId, agencyId) lookup, returning plaintext password and mfaSecret. The 3-tuple is index-served by tac_unique_active_per_agency. Throws if no active credential matches. APPROVAL_REQUIRED. Plaintext fields are camelCase-named (`password`, `mfaSecret`) so the audit row's outputs JSONB shows them as [redacted] (R13 mitigation).
Resolve and fetch a credential by (tenantId, entityId, agencyId) lookup, returning plaintext password and mfaSecret. The 3-tuple is index-served by tac_unique_active_per_agency. Throws if no active credential matches. APPROVAL_REQUIRED. Plaintext fields are camelCase-named (`password`, `mfaSecret`) so the audit row's outputs JSONB shows them as [redacted] (R13 mitigation).
Request body CredentialVaultGetCredentialByEntityInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
entityId | string | required | — |
agencyId | string | required | — |
purpose | string | required | — |
Responses
- 200Successful invocation
CredentialVaultGetCredentialByEntityOutputField Type Required Description idstringrequired — tenant_idstringrequired — employer_entity_idstringrequired — agency_idstringrequired — account_numberstringrequired — login_usernamestringrequired — has_passwordbooleanrequired — has_mfa_secretbooleanrequired — has_backup_codesbooleanrequired — last_login_atstringrequired — last_password_change_atstringrequired — refresh_required_bystringrequired — statusenum: "active" | "revoked" | "refresh_required" | "locked"required — notesstringrequired — created_atstringrequired — updated_atstringrequired — passwordstringrequired — mfaSecretstringrequired — backupCodesstringrequired — health_check_auto_flipbooleanoptional — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/credential-vault.listCredentialsList credentials in the caller's tenant. Returns metadata only (no plaintext, no vault secret_ids). AUTONOMOUS — agents may call freely. Pass `entityId` to scope to a single employer; pass `statuses` to widen beyond the default `active` filter.
List credentials in the caller's tenant. Returns metadata only (no plaintext, no vault secret_ids). AUTONOMOUS — agents may call freely. Pass `entityId` to scope to a single employer; pass `statuses` to widen beyond the default `active` filter.
Request body CredentialVaultListCredentialsInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
entityId | string | optional | — |
statuses | array<enum: "active" | "revoked" | "refresh_required" | "locked"> | optional | — |
Responses
- 200Successful invocation
CredentialVaultListCredentialsOutputField Type Required Description credentialsarray<object>required — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/credential-vault.listCredentialsExpiringSoonList active credentials whose refresh_required_by falls within the next `daysAhead` days. Used by the auto-refresh job (plan §6 D4). AUTONOMOUS.
List active credentials whose refresh_required_by falls within the next `daysAhead` days. Used by the auto-refresh job (plan §6 D4). AUTONOMOUS.
Request body CredentialVaultListCredentialsExpiringSoonInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
daysAhead | integer | required | — |
Responses
- 200Successful invocation
CredentialVaultListCredentialsExpiringSoonOutputField Type Required Description credentialsarray<object>required — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/credential-vault.updateCredentialUpdate credential metadata and/or rotate plaintext password / mfaSecret. APPROVAL_REQUIRED. Plaintext rotations go through vault.update_secret; the secret_id on the credential row is preserved so audit trails remain stable.
Update credential metadata and/or rotate plaintext password / mfaSecret. APPROVAL_REQUIRED. Plaintext rotations go through vault.update_secret; the secret_id on the credential row is preserved so audit trails remain stable.
Request body CredentialVaultUpdateCredentialInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
credentialId | string | required | — |
patch | object | required | — |
Responses
- 200Successful invocation
CredentialVaultUpdateCredentialOutputField Type Required Description idstringrequired — tenant_idstringrequired — employer_entity_idstringrequired — agency_idstringrequired — account_numberstringrequired — login_usernamestringrequired — has_passwordbooleanrequired — has_mfa_secretbooleanrequired — has_backup_codesbooleanrequired — last_login_atstringrequired — last_password_change_atstringrequired — refresh_required_bystringrequired — statusenum: "active" | "revoked" | "refresh_required" | "locked"required — notesstringrequired — created_atstringrequired — updated_atstringrequired — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/credential-vault.revokeCredentialSet status='revoked' on a credential AND overwrite the plaintext in Supabase Vault with a tombstone marker. The vault secret_ids stay on the credential row so the audit trail can resolve which credential a historical event referenced, but the actual plaintext is unrecoverable after revoke. Aligns with GDPR Art. 17 / CCPA right-to-erasure. APPROVAL_REQUIRED. PR #466 review Bug 4.
Set status='revoked' on a credential AND overwrite the plaintext in Supabase Vault with a tombstone marker. The vault secret_ids stay on the credential row so the audit trail can resolve which credential a historical event referenced, but the actual plaintext is unrecoverable after revoke. Aligns with GDPR Art. 17 / CCPA right-to-erasure. APPROVAL_REQUIRED. PR #466 review Bug 4.
Request body CredentialVaultRevokeCredentialInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
credentialId | string | required | — |
Responses
- 200Successful invocation
CredentialVaultRevokeCredentialOutputField Type Required Description idstringrequired — tenant_idstringrequired — employer_entity_idstringrequired — agency_idstringrequired — account_numberstringrequired — login_usernamestringrequired — has_passwordbooleanrequired — has_mfa_secretbooleanrequired — has_backup_codesbooleanrequired — last_login_atstringrequired — last_password_change_atstringrequired — refresh_required_bystringrequired — statusenum: "active" | "revoked" | "refresh_required" | "locked"required — notesstringrequired — created_atstringrequired — updated_atstringrequired — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/credential-vault.markRefreshRequiredFlip a credential to status='refresh_required' and set refresh_required_by=now(). Lighter-risk than other write methods because no plaintext is touched — just state. NOTIFY.
Flip a credential to status='refresh_required' and set refresh_required_by=now(). Lighter-risk than other write methods because no plaintext is touched — just state. NOTIFY.
Request body CredentialVaultMarkRefreshRequiredInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
credentialId | string | required | — |
Responses
- 200Successful invocation
CredentialVaultMarkRefreshRequiredOutputField Type Required Description idstringrequired — tenant_idstringrequired — employer_entity_idstringrequired — agency_idstringrequired — account_numberstringrequired — login_usernamestringrequired — has_passwordbooleanrequired — has_mfa_secretbooleanrequired — has_backup_codesbooleanrequired — last_login_atstringrequired — last_password_change_atstringrequired — refresh_required_bystringrequired — statusenum: "active" | "revoked" | "refresh_required" | "locked"required — notesstringrequired — created_atstringrequired — updated_atstringrequired — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/credential-vault.getCurrentOtpReturn the current RFC-6238 TOTP code for a credential's stored authenticator (MFA) seed, plus seconds remaining in the period. Returns { code: null, secondsRemaining: 0 } when the credential has no stored MFA seed. APPROVAL_REQUIRED — it reads decrypted credential auth material from the vault.
Return the current RFC-6238 TOTP code for a credential's stored authenticator (MFA) seed, plus seconds remaining in the period. Returns { code: null, secondsRemaining: 0 } when the credential has no stored MFA seed. APPROVAL_REQUIRED — it reads decrypted credential auth material from the vault.
Request body CredentialVaultGetCurrentOtpInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
credentialId | string | required | — |
Responses
- 200Successful invocation
CredentialVaultGetCurrentOtpOutputField Type Required Description codestringrequired — secondsRemainingintegerrequired — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/credential-vault.getHealthCheckPolicyRead the per-agency health-check status-mutation policy for the caller's tenant. AUTONOMOUS — read-only config. Returns statusMutationEnabled=false (record-only, the safe default) when no policy row exists for the agency.
Read the per-agency health-check status-mutation policy for the caller's tenant. AUTONOMOUS — read-only config. Returns statusMutationEnabled=false (record-only, the safe default) when no policy row exists for the agency.
Request body CredentialVaultGetHealthCheckPolicyInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
agencyId | string | required | — |
Responses
- 200Successful invocation
CredentialVaultGetHealthCheckPolicyOutputField Type Required Description agencyIdstringrequired — statusMutationEnabledbooleanrequired — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/credential-vault.setHealthCheckPolicyEnable/disable health-check status auto-flip for one agency in the caller's tenant. NOTIFY — a config write that should be human-visible. Enable only for portals whose invalidSignal coverage is proven (un-hardened portals stay record-only). Upserts the per-(tenant, agency) policy row.
Enable/disable health-check status auto-flip for one agency in the caller's tenant. NOTIFY — a config write that should be human-visible. Enable only for portals whose invalidSignal coverage is proven (un-hardened portals stay record-only). Upserts the per-(tenant, agency) policy row.
Request body CredentialVaultSetHealthCheckPolicyInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
agencyId | string | required | — |
statusMutationEnabled | boolean | required | — |
Responses
- 200Successful invocation
CredentialVaultSetHealthCheckPolicyOutputField Type Required Description agencyIdstringrequired — statusMutationEnabledbooleanrequired — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/credential-vault.useUse a stored credential BY REFERENCE to drive an authenticated portal login: dispatches the portal-execution job and returns the job id only. The plaintext secret is decrypted exclusively inside the portal worker and never appears in this method's output. Use when a filing or protest flow needs an authenticated portal session.
Use a stored credential BY REFERENCE to drive an authenticated portal login: dispatches the portal-execution job and returns the job id only. The plaintext secret is decrypted exclusively inside the portal worker and never appears in this method's output. Use when a filing or protest flow needs an authenticated portal session.
Request body CredentialVaultUseInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
credentialId | string | required | — |
purpose | string | required | — |
dedupeToken | string | required | — |
Responses
- 200Successful invocation
CredentialVaultUseOutputField Type Required Description jobIdstringrequired — deduplicatedbooleanrequired — credentialIdstringrequired — agencyIdstringrequired — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/credential-vault.rotateRotate a stored portal password BY REFERENCE: dispatches the transactional rotation job (login, change-password, verify-login in one governed session) and returns the job id only. The new secret is generated inside the worker and never appears anywhere outside the vault and the portal DOM. Use when a credential is suspected compromised or a portal's password-age policy requires a change.
Rotate a stored portal password BY REFERENCE: dispatches the transactional rotation job (login, change-password, verify-login in one governed session) and returns the job id only. The new secret is generated inside the worker and never appears anywhere outside the vault and the portal DOM. Use when a credential is suspected compromised or a portal's password-age policy requires a change.
Request body CredentialVaultRotateInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
credentialId | string | required | — |
reason | string | optional | — |
Responses
- 200Successful invocation
CredentialVaultRotateOutputField Type Required Description jobIdstringrequired — deduplicatedbooleanrequired — credentialIdstringrequired — agencyIdstringrequired — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/credential-vault.healthReport a credential's login health from the latest lockout-aware scheduled probe (the hourly health cron is the only thing that actually logs in — this read never touches the portal, so it can never contribute to a lockout). Use to surface which credentials need attention before relying on one for a filing. 'uncertain' means no probe evidence — never treat it as healthy.
Report a credential's login health from the latest lockout-aware scheduled probe (the hourly health cron is the only thing that actually logs in — this read never touches the portal, so it can never contribute to a lockout). Use to surface which credentials need attention before relying on one for a filing. 'uncertain' means no probe evidence — never treat it as healthy.
Request body CredentialVaultHealthInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
credentialId | string | required | — |
Responses
- 200Successful invocation
CredentialVaultHealthOutputField Type Required Description credentialIdstringrequired — statusstringrequired — healthenum: "pass" | "fail" | "uncertain"required — lastHealthCheckAtstringrequired — lastHealthCheckOutcomestringrequired — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/credential-vault.revealReveal a credential's plaintext to an authorized human screen. Requires a typed reason and passes the account's reveal-visibility policy for VAULT_V1 tenants; the hash-chained evidence row is written BEFORE decryption and the reveal is refused if it cannot be. APPROVAL_REQUIRED — UI-only, never exposed via MCP or CLI.
Reveal a credential's plaintext to an authorized human screen. Requires a typed reason and passes the account's reveal-visibility policy for VAULT_V1 tenants; the hash-chained evidence row is written BEFORE decryption and the reveal is refused if it cannot be. APPROVAL_REQUIRED — UI-only, never exposed via MCP or CLI.
Request body CredentialVaultRevealInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
credentialId | string | required | — |
reason | string | optional | — |
ipAddress | string | optional | — |
userAgent | string | optional | — |
Responses
- 200Successful invocation
CredentialVaultRevealOutputField Type Required Description idstringrequired — tenant_idstringrequired — employer_entity_idstringrequired — agency_idstringrequired — account_numberstringrequired — login_usernamestringrequired — has_passwordbooleanrequired — has_mfa_secretbooleanrequired — has_backup_codesbooleanrequired — last_login_atstringrequired — last_password_change_atstringrequired — refresh_required_bystringrequired — statusenum: "active" | "revoked" | "refresh_required" | "locked"required — notesstringrequired — created_atstringrequired — updated_atstringrequired — passwordstringrequired — mfaSecretstringrequired — backupCodesstringrequired — health_check_auto_flipbooleanoptional — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
l2:edelivery10
POST/v1/edelivery.listEdeliveryRulesBrowse the e-delivery catalog (state_edelivery_rules, global config — NO tenant filter). Optional filters: stateCode, requirementType, verificationStatus. Returns matching rows plus HONEST per-status counts ({unverified, human_reviewed, verified}) — never a 'done/complete' claim. AUTONOMOUS, read-only.
Browse the e-delivery catalog (state_edelivery_rules, global config — NO tenant filter). Optional filters: stateCode, requirementType, verificationStatus. Returns matching rows plus HONEST per-status counts ({unverified, human_reviewed, verified}) — never a 'done/complete' claim. AUTONOMOUS, read-only.
Request body EdeliveryListEdeliveryRulesInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
stateCode | string | optional | — |
requirementType | enum: "sui_registration" | "withholding_registration" | "workers_comp" | "pfml" | … | optional | — |
verificationStatus | enum: "unverified" | "human_reviewed" | "verified" | optional | — |
Responses
- 200Successful invocation
EdeliveryListEdeliveryRulesOutputField Type Required Description rowsarray<object>required — countsobjectrequired — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/edelivery.getEdeliveryRuleRead one e-delivery catalog cell (state_edelivery_rules, global config — NO tenant filter): the rule row plus its typed ordered enrollment steps. Cell absent → honest null + [] (never invented data). AUTONOMOUS, read-only.
Read one e-delivery catalog cell (state_edelivery_rules, global config — NO tenant filter): the rule row plus its typed ordered enrollment steps. Cell absent → honest null + [] (never invented data). AUTONOMOUS, read-only.
Request body EdeliveryGetEdeliveryRuleInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
stateCode | string | required | — |
requirementType | enum: "sui_registration" | "withholding_registration" | "workers_comp" | "pfml" | … | required | — |
Responses
- 200Successful invocation
EdeliveryGetEdeliveryRuleOutputField Type Required Description ruleobjectrequired — stepsarray<object>required — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/edelivery.proposeEdeliveryRuleResearch one (state, requirement) cell's PAPERLESS/e-delivery facts via the Claude + web_search agent and upsert an UNVERIFIED proposal onto state_edelivery_rules BY PK (global config — NO tenant filter). The write ALWAYS leaves verification_status='unverified' and NEVER sets verified/human_reviewed (agents may never verify); writes provenance (source_url + retrieved_at); idempotent-by-PK. MUST NOT downgrade a human-verified cell: returns the existing row + the fresh proposal so a human can compare. PII-free. NOTIFY: agents may call; a human reviews before promotion.
Research one (state, requirement) cell's PAPERLESS/e-delivery facts via the Claude + web_search agent and upsert an UNVERIFIED proposal onto state_edelivery_rules BY PK (global config — NO tenant filter). The write ALWAYS leaves verification_status='unverified' and NEVER sets verified/human_reviewed (agents may never verify); writes provenance (source_url + retrieved_at); idempotent-by-PK. MUST NOT downgrade a human-verified cell: returns the existing row + the fresh proposal so a human can compare. PII-free. NOTIFY: agents may call; a human reviews before promotion.
Request body EdeliveryProposeEdeliveryRuleInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
stateCode | string | required | — |
requirementType | enum: "sui_registration" | "withholding_registration" | "workers_comp" | "pfml" | … | required | — |
Responses
- 200Successful invocation
EdeliveryProposeEdeliveryRuleOutputField Type Required Description rowobjectrequired — proposalobjectrequired — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/edelivery.promoteEdeliveryRuleHuman gate: promote an e-delivery cell along the verification ladder (unverified → human_reviewed → verified). APPROVAL_REQUIRED, UI-only — excluded from MCP/CLI, and the handler REJECTS any non-human principal before any write. Verifying requires provenance (source_url + retrieved_at). Stamps reviewed_by / last_reviewed_at, and on verify also verified_at / verified_by.
Human gate: promote an e-delivery cell along the verification ladder (unverified → human_reviewed → verified). APPROVAL_REQUIRED, UI-only — excluded from MCP/CLI, and the handler REJECTS any non-human principal before any write. Verifying requires provenance (source_url + retrieved_at). Stamps reviewed_by / last_reviewed_at, and on verify also verified_at / verified_by.
Request body EdeliveryPromoteEdeliveryRuleInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
stateCode | string | required | — |
requirementType | enum: "sui_registration" | "withholding_registration" | "workers_comp" | "pfml" | … | required | — |
toStatus | enum: "human_reviewed" | "verified" | required | — |
reason | string | optional | — |
Responses
- 200Successful invocation
EdeliveryPromoteEdeliveryRuleOutputField Type Required Description stateCodestringrequired — requirementTypeenum: "sui_registration" | "withholding_registration" | "workers_comp" | "pfml" | …required — fromStatusenum: "unverified" | "human_reviewed" | "verified"required — toStatusenum: "unverified" | "human_reviewed" | "verified"required — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/edelivery.listEdeliveryEnrollmentsList the per-entity e-delivery enrollment checklist (tenant+entity scoped), idempotently seeding missing (state, requirement) items from the employer's footprint (employer_state_registrations + states_operated; v1 scope = SUI + withholding). Each item carries its catalog cell's facts FAIL-CLOSED: enrollment steps are attached ONLY when the cell is verified — unverified facts never render as authoritative. AUTONOMOUS, read-mostly.
List the per-entity e-delivery enrollment checklist (tenant+entity scoped), idempotently seeding missing (state, requirement) items from the employer's footprint (employer_state_registrations + states_operated; v1 scope = SUI + withholding). Each item carries its catalog cell's facts FAIL-CLOSED: enrollment steps are attached ONLY when the cell is verified — unverified facts never render as authoritative. AUTONOMOUS, read-mostly.
Request body EdeliveryListEdeliveryEnrollmentsInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
entityId | string | required | — |
Responses
- 200Successful invocation
EdeliveryListEdeliveryEnrollmentsOutputField Type Required Description entityIdstringrequired — intakeEmailstringrequired — itemsarray<object>required — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/edelivery.listEdeliveryEnrollmentsReadonlyRead an entity's e-delivery enrollment checklist WITHOUT seeding (the employer-portal spectator view). Returns the persisted items the CPA/Kreto-ops maintains, each with its catalog facts FAIL-CLOSED: authoritative steps only on verified cells, unverified steps under `draftSteps` for the 'unverified draft' banner. AUTONOMOUS, read-only.
Read an entity's e-delivery enrollment checklist WITHOUT seeding (the employer-portal spectator view). Returns the persisted items the CPA/Kreto-ops maintains, each with its catalog facts FAIL-CLOSED: authoritative steps only on verified cells, unverified steps under `draftSteps` for the 'unverified draft' banner. AUTONOMOUS, read-only.
Request body EdeliveryListEdeliveryEnrollmentsReadonlyInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
entityId | string | required | — |
Responses
- 200Successful invocation
EdeliveryListEdeliveryEnrollmentsReadonlyOutputField Type Required Description entityIdstringrequired — intakeEmailstringrequired — itemsarray<object>required — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/edelivery.setEnrollmentStatusSet one e-delivery checklist item's status (not_started | enrolled) with human attribution (completed_by = the session user on enroll). Tenant+entity scoped. Appends a hash-chained audit_events row — enrollment status is a compliance-posture claim. NOTIFY. The customer performed the enrollment in the agency portal; Kreto only records it.
Set one e-delivery checklist item's status (not_started | enrolled) with human attribution (completed_by = the session user on enroll). Tenant+entity scoped. Appends a hash-chained audit_events row — enrollment status is a compliance-posture claim. NOTIFY. The customer performed the enrollment in the agency portal; Kreto only records it.
Request body EdeliverySetEnrollmentStatusInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
entityId | string | required | — |
itemId | string | required | — |
status | enum: "not_started" | "enrolled" | required | — |
Responses
- 200Successful invocation
EdeliverySetEnrollmentStatusOutputField Type Required Description itemIdstringrequired — stateCodestringrequired — requirementTypeenum: "sui_registration" | "withholding_registration" | "workers_comp" | "pfml" | …required — statusenum: "not_started" | "enrolled"required — completedAtstringrequired — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/edelivery.listFetchQueueList the tenant's OPEN Portal-pickup tasks: inbound agency notification emails ('you have new correspondence — log in') that carried no document (inbound_emails processing_status='notification_only', unresolved). Optional entityId filter. The row IS the task — a notice is only ever created when the fetched document arrives. AUTONOMOUS, read-only.
List the tenant's OPEN Portal-pickup tasks: inbound agency notification emails ('you have new correspondence — log in') that carried no document (inbound_emails processing_status='notification_only', unresolved). Optional entityId filter. The row IS the task — a notice is only ever created when the fetched document arrives. AUTONOMOUS, read-only.
Request body EdeliveryListFetchQueueInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
entityId | string | optional | — |
Responses
- 200Successful invocation
EdeliveryListFetchQueueOutputField Type Required Description tasksarray<object>required — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/edelivery.resolveFetchTaskResolve one Portal-pickup task (inbound_emails processing_status='notification_only'): stamps resolved_at/resolved_by and optionally back-links the notice created when the customer fetched the document (the noticeId must belong to the caller's tenant). Tenant-scoped. NOTIFY.
Resolve one Portal-pickup task (inbound_emails processing_status='notification_only'): stamps resolved_at/resolved_by and optionally back-links the notice created when the customer fetched the document (the noticeId must belong to the caller's tenant). Tenant-scoped. NOTIFY.
Request body EdeliveryResolveFetchTaskInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
taskId | string | required | — |
noticeId | string | optional | — |
Responses
- 200Successful invocation
EdeliveryResolveFetchTaskOutputField Type Required Description taskIdstringrequired — resolvedAtstringrequired — noticeIdstringrequired — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/edelivery.enrollViaKretoOpsKreto ops performs an agency-portal paperless enrollment ON THE CUSTOMER'S BEHALF under an explicit consent artifact + stored portal credentials. APPROVAL_REQUIRED, UI-only — excluded from MCP/CLI, and the handler REJECTS any non-human principal before any write. Records an IMMUTABLE per-enrollment consent (who consented, when, IP/UA, scope) and flips the checklist item to enrolled, attributed to ops. HONESTY: customer-facing copy stays 'the customer performs' until this flow is enabled + verified.
Kreto ops performs an agency-portal paperless enrollment ON THE CUSTOMER'S BEHALF under an explicit consent artifact + stored portal credentials. APPROVAL_REQUIRED, UI-only — excluded from MCP/CLI, and the handler REJECTS any non-human principal before any write. Records an IMMUTABLE per-enrollment consent (who consented, when, IP/UA, scope) and flips the checklist item to enrolled, attributed to ops. HONESTY: customer-facing copy stays 'the customer performs' until this flow is enabled + verified.
Request body EdeliveryEnrollViaKretoOpsInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
entityId | string | required | — |
stateCode | string | required | — |
requirementType | enum: "sui_registration" | "withholding_registration" | "workers_comp" | "pfml" | … | required | — |
consentedByUserId | string | required | — |
consentIp | string | optional | — |
consentUserAgent | string | optional | — |
Responses
- 200Successful invocation
EdeliveryEnrollViaKretoOpsOutputField Type Required Description consentIdstringrequired — itemIdstringrequired — stateCodestringrequired — requirementTypeenum: "sui_registration" | "withholding_registration" | "workers_comp" | "pfml" | …required — statusenum: "not_started" | "enrolled"required — enrolledViaOpsbooleanrequired — reusedExistingConsentbooleanrequired — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
l2:employee-roster6
POST/v1/employee-roster.getActiveRosterList employees on the active roster for the caller's tenant. Defaults to employment_status='active'; pass `statuses` to widen (e.g. ['active','terminated','leave'] for the I-9 list). Pass `entityIds` to narrow to a subset of entities the caller has access to. If `asOf` is supplied, joins payroll_pay_periods to detect employees who had a paycheck within 60 days of asOf and weren't terminated before it.
List employees on the active roster for the caller's tenant. Defaults to employment_status='active'; pass `statuses` to widen (e.g. ['active','terminated','leave'] for the I-9 list). Pass `entityIds` to narrow to a subset of entities the caller has access to. If `asOf` is supplied, joins payroll_pay_periods to detect employees who had a paycheck within 60 days of asOf and weren't terminated before it.
Request body EmployeeRosterGetActiveRosterInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
asOf | string · date-time | optional | — |
entityIds | array<string · uuid> | optional | — |
statuses | array<enum: "active" | "terminated" | "leave"> | optional | — |
Responses
- 200Successful invocation
EmployeeRosterGetActiveRosterOutputField Type Required Description employeesarray<object>required — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/employee-roster.getEmployeeFetch a single employee by id, scoped to the caller's tenant. Returns null if no row matches. Per README §6 Q5, no asOf is supported on this method; per-employee historical context comes from payroll_pay_periods joins, not effective-dating columns.
Fetch a single employee by id, scoped to the caller's tenant. Returns null if no row matches. Per README §6 Q5, no asOf is supported on this method; per-employee historical context comes from payroll_pay_periods joins, not effective-dating columns.
Request body EmployeeRosterGetEmployeeInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
employeeId | string · uuid | required | — |
Responses
- 200Successful invocation
EmployeeRosterGetEmployeeOutputField Type Required Description idstring · uuidrequired — entity_idstring · uuidrequired — ssn_last4stringrequired — full_namestringrequired — emailstringrequired — departmentstringrequired — hire_datestringrequired — termination_datestringrequired — employment_statusenum: "active" | "terminated" | "leave"required — work_statestringrequired — home_statestringrequired — salary_typeenum: "hourly" | "salary" | "unknown"required — hourly_ratenumberrequired — annual_salarynumberrequired — i9_section1_completebooleanrequired — i9_section2_completebooleanrequired — i9_reverification_neededbooleanrequired — work_auth_typestringrequired — work_auth_expirystringrequired — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/employee-roster.getEmployeesByStateList employees whose canonical work_state matches the supplied two-letter code (e.g. 'OH'). asOf is optional; without it, the active roster filtered by work_state is returned. With asOf, the asOf logic from getActiveRoster applies first, then the work_state filter narrows the result.
List employees whose canonical work_state matches the supplied two-letter code (e.g. 'OH'). asOf is optional; without it, the active roster filtered by work_state is returned. With asOf, the asOf logic from getActiveRoster applies first, then the work_state filter narrows the result.
Request body EmployeeRosterGetEmployeesByStateInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
state | string | required | — |
asOf | string · date-time | optional | — |
Responses
- 200Successful invocation
EmployeeRosterGetEmployeesByStateOutputField Type Required Description employeesarray<object>required — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/employee-roster.countEmployeesCount active employees on the caller's tenant. Pass `entityId` to scope to a single employer (PEPM Source 3 pattern). Replaces the ad-hoc count query in src/lib/billing/pepm-quantity.ts — migrated in Part F (KRT-1159). asOf is supported via the same join-with-payroll_pay_periods logic getActiveRoster uses.
Count active employees on the caller's tenant. Pass `entityId` to scope to a single employer (PEPM Source 3 pattern). Replaces the ad-hoc count query in src/lib/billing/pepm-quantity.ts — migrated in Part F (KRT-1159). asOf is supported via the same join-with-payroll_pay_periods logic getActiveRoster uses.
Request body EmployeeRosterCountEmployeesInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
asOf | string · date-time | optional | — |
entityId | string · uuid | optional | — |
Responses
- 200Successful invocation
EmployeeRosterCountEmployeesOutputField Type Required Description countintegerrequired — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/employee-roster.getStateChangesDetect work_state transitions across employees by walking payroll_pay_periods paycheck history since the supplied date. Returns one StateChangeEvent per detected transition (e.g. an employee moving MA→KS mid-quarter). The trigger source for the Phase 1+ state-registration agent.
Detect work_state transitions across employees by walking payroll_pay_periods paycheck history since the supplied date. Returns one StateChangeEvent per detected transition (e.g. an employee moving MA→KS mid-quarter). The trigger source for the Phase 1+ state-registration agent.
Request body EmployeeRosterGetStateChangesInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
since | string · date-time | required | — |
Responses
- 200Successful invocation
EmployeeRosterGetStateChangesOutputField Type Required Description changesarray<object>required — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/employee-roster.getRosterWithSsnHashRoster rows for a single entity, with `ssn_hash` exposed in addition to the public EmployeeRosterRow fields. ELEVATED risk: ssn_hash is the cross-payroll-graph join key but is NOT part of the public PII contract. Use only from cross-reference / audit-defense consumers. Filters by employment_status='active' by default; with `asOf`, applies the same payroll_pay_periods liveness heuristic getActiveRoster uses. Excludes rows whose ssn_hash is NULL (those rows can't be joined against the payroll fact graph anyway).
Roster rows for a single entity, with `ssn_hash` exposed in addition to the public EmployeeRosterRow fields. ELEVATED risk: ssn_hash is the cross-payroll-graph join key but is NOT part of the public PII contract. Use only from cross-reference / audit-defense consumers. Filters by employment_status='active' by default; with `asOf`, applies the same payroll_pay_periods liveness heuristic getActiveRoster uses. Excludes rows whose ssn_hash is NULL (those rows can't be joined against the payroll fact graph anyway).
Request body EmployeeRosterGetRosterWithSsnHashInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
entityId | string · uuid | required | — |
asOf | string · date-time | optional | — |
Responses
- 200Successful invocation
EmployeeRosterGetRosterWithSsnHashOutputField Type Required Description employeesarray<object>required — - 400Validation error (input schema rejected). risk_level=elevated.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
l2:foreign-qualification13
POST/v1/foreign-qualification.listForeignQualRulesList the state foreign-qualification catalog (global config): per-(state, entity_kind) SOS certificate-of-authority rules — agency, form, state filing fee, good-standing prerequisite and doing-business notes — with the verification ladder status of every cell and honest per-status counts. Cells below the display gate (human_reviewed) must never be rendered as authoritative to customers.
List the state foreign-qualification catalog (global config): per-(state, entity_kind) SOS certificate-of-authority rules — agency, form, state filing fee, good-standing prerequisite and doing-business notes — with the verification ladder status of every cell and honest per-status counts. Cells below the display gate (human_reviewed) must never be rendered as authoritative to customers.
Request body ForeignQualificationListForeignQualRulesInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
stateCode | string | optional | — |
entityKind | enum: "corporation" | "llc" | "nonprofit" | "lp" | … | optional | — |
verificationStatus | enum: "unverified" | "human_reviewed" | "verified" | optional | — |
Responses
- 200Successful invocation
ForeignQualificationListForeignQualRulesOutputField Type Required Description rulesarray<object>required — countsobjectrequired — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/foreign-qualification.getForeignQualRuleFetch one foreign-qualification catalog cell with the (state, entity_kind) → (state, 'default') fallback. Null rule = no catalog coverage yet. Advisory context only — doing_business_notes never assert an obligation.
Fetch one foreign-qualification catalog cell with the (state, entity_kind) → (state, 'default') fallback. Null rule = no catalog coverage yet. Advisory context only — doing_business_notes never assert an obligation.
Request body ForeignQualificationGetForeignQualRuleInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
stateCode | string | required | — |
entityKind | enum: "corporation" | "llc" | "nonprofit" | "lp" | … | optional | — |
Responses
- 200Successful invocation
ForeignQualificationGetForeignQualRuleOutputField Type Required Description ruleobjectrequired — usedDefaultFallbackbooleanrequired — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/foreign-qualification.proposeForeignQualRuleResearch-agent write path for the foreign-qualification catalog. Upserts one (state, entity_kind) cell as verification_status='unverified' with mandatory provenance (source_url + retrieved_at). REFUSES to touch a cell already at human_reviewed/verified — verified cells are never downgraded (AC-22 clone); corrections go through the review queue.
Research-agent write path for the foreign-qualification catalog. Upserts one (state, entity_kind) cell as verification_status='unverified' with mandatory provenance (source_url + retrieved_at). REFUSES to touch a cell already at human_reviewed/verified — verified cells are never downgraded (AC-22 clone); corrections go through the review queue.
Request body ForeignQualificationProposeForeignQualRuleInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
stateCode | string | required | — |
entityKind | enum: "corporation" | "llc" | "nonprofit" | "lp" | … | optional | — |
agencyCode | string | required | — |
agencyName | string | required | — |
portalUrl | string · uri | optional | — |
formName | string | optional | — |
filingFeeUsd | number | optional | — |
expediteFeeNotes | string | optional | — |
goodStandingRequired | boolean | optional | — |
goodStandingMaxAgeDays | integer | optional | — |
registeredAgentRequired | boolean | optional | — |
nameCheckNotes | string | optional | — |
doingBusinessNotes | string | optional | — |
penaltyNotes | string | optional | — |
processingTimeNotes | string | optional | — |
sourceUrl | string · uri | required | — |
retrievedAt | string · date-time | required | — |
notes | string | optional | — |
Responses
- 200Successful invocation
ForeignQualificationProposeForeignQualRuleOutputField Type Required Description ruleobjectrequired — createdbooleanrequired — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/foreign-qualification.promoteForeignQualRulePromote a foreign-qualification catalog cell along the verification ladder (unverified → human_reviewed → verified). APPROVAL_REQUIRED and UI-only: the handler rejects any non-human principal (AC-20 clone) and refuses cells with no source_url provenance (CWE-345).
Promote a foreign-qualification catalog cell along the verification ladder (unverified → human_reviewed → verified). APPROVAL_REQUIRED and UI-only: the handler rejects any non-human principal (AC-20 clone) and refuses cells with no source_url provenance (CWE-345).
Request body ForeignQualificationPromoteForeignQualRuleInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
stateCode | string | required | — |
entityKind | enum: "corporation" | "llc" | "nonprofit" | "lp" | … | optional | — |
targetStatus | enum: "human_reviewed" | "verified" | required | — |
reviewerEmail | string · email | required | — |
reason | string | required | — |
Responses
- 200Successful invocation
ForeignQualificationPromoteForeignQualRuleOutputField Type Required Description ruleobjectrequired — fromStatusenum: "unverified" | "human_reviewed" | "verified"required — toStatusenum: "unverified" | "human_reviewed" | "verified"required — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/foreign-qualification.listForeignQualificationsList the tenant's foreign-qualification tracker rows (once per entity × state), filterable by entity, state, status and obligation assessment. Advisory rows are unconfirmed legal judgments — callers must exclude them from compliance/on-track counts (design D5/D6). Paginated (default 25). Tenant-scoped via the invocation context.
List the tenant's foreign-qualification tracker rows (once per entity × state), filterable by entity, state, status and obligation assessment. Advisory rows are unconfirmed legal judgments — callers must exclude them from compliance/on-track counts (design D5/D6). Paginated (default 25). Tenant-scoped via the invocation context.
Request body ForeignQualificationListForeignQualificationsInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
entityId | string | optional | — |
stateCode | string | optional | — |
status | enum: "pending" | "prepared" | "submitted" | "approved" | … | optional | — |
obligationAssessment | enum: "advisory" | "confirmed" | "not_required" | optional | — |
excludeAdvisory | boolean | optional | — |
limit | integer | optional | — |
offset | integer | optional | — |
Responses
- 200Successful invocation
ForeignQualificationListForeignQualificationsOutputField Type Required Description qualificationsarray<object>required — totalnumberrequired — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/foreign-qualification.getForeignQualificationsByEntityFetch every foreign-qualification tracker row for one entity (optionally one state) — advisory, confirmed, dismissed and recorded qualifications. Tenant-scoped.
Fetch every foreign-qualification tracker row for one entity (optionally one state) — advisory, confirmed, dismissed and recorded qualifications. Tenant-scoped.
Request body ForeignQualificationGetForeignQualificationsByEntityInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
entityId | string | required | — |
stateCode | string | optional | — |
Responses
- 200Successful invocation
ForeignQualificationGetForeignQualificationsByEntityOutputField Type Required Description qualificationsarray<object>required — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/foreign-qualification.detectForeignQualNeedsDry-run compute of an entity's foreign-qualification detection signal (design §4): per candidate state, whether the advisory signal fires (operating evidence outside the formation state with no qualification on record) or an explicit disposition (already_tracked / not_foreign / no_signal / needs_input when the formation state is unknown). Writes NOTHING — the sweep's detection roll persists advisory rows; this method answers 'what would be flagged?'. ADVISORY POSTURE: a firing signal is never an obligation assertion — a human CPA confirms.
Dry-run compute of an entity's foreign-qualification detection signal (design §4): per candidate state, whether the advisory signal fires (operating evidence outside the formation state with no qualification on record) or an explicit disposition (already_tracked / not_foreign / no_signal / needs_input when the formation state is unknown). Writes NOTHING — the sweep's detection roll persists advisory rows; this method answers 'what would be flagged?'. ADVISORY POSTURE: a firing signal is never an obligation assertion — a human CPA confirms.
Request body ForeignQualificationDetectForeignQualNeedsInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
entityId | string | required | — |
Responses
- 200Successful invocation
ForeignQualificationDetectForeignQualNeedsOutputField Type Required Description resultobjectrequired — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/foreign-qualification.createForeignQualificationCreate one manual foreign-qualification tracker row (source='manual') for an entity × state. Defaults to obligation_assessment='advisory'; creating a CONFIRMED row is a human CPA judgment and rejects agent principals (design D5). Duplicate states are rejected by the once-per-state UNIQUE.
Create one manual foreign-qualification tracker row (source='manual') for an entity × state. Defaults to obligation_assessment='advisory'; creating a CONFIRMED row is a human CPA judgment and rejects agent principals (design D5). Duplicate states are rejected by the once-per-state UNIQUE.
Request body ForeignQualificationCreateForeignQualificationInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
entityId | string | required | — |
stateCode | string | required | — |
obligationAssessment | enum: "advisory" | "confirmed" | optional | — |
assessmentNote | string | optional | — |
notes | string | optional | — |
Responses
- 200Successful invocation
ForeignQualificationCreateForeignQualificationOutputField Type Required Description qualificationobjectrequired — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/foreign-qualification.recordExistingQualificationRecord an ALREADY-HELD foreign qualification (design D12 backfill): the row lands status='approved', obligation_assessment='confirmed', source='manual' with the state-issued qualification_date + sos_file_number. This is the authoritative annual-reports foreign anchor (design D9) and permanently suppresses detection advisories for the state (once-per-state UNIQUE).
Record an ALREADY-HELD foreign qualification (design D12 backfill): the row lands status='approved', obligation_assessment='confirmed', source='manual' with the state-issued qualification_date + sos_file_number. This is the authoritative annual-reports foreign anchor (design D9) and permanently suppresses detection advisories for the state (once-per-state UNIQUE).
Request body ForeignQualificationRecordExistingQualificationInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
entityId | string | required | — |
stateCode | string | required | — |
qualificationDate | string | required | — |
sosFileNumber | string | optional | — |
notes | string | optional | — |
Responses
- 200Successful invocation
ForeignQualificationRecordExistingQualificationOutputField Type Required Description qualificationobjectrequired — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/foreign-qualification.updateForeignQualificationMetadataEdit tracker metadata on one foreign-qualification row: the obligation assessment (confirm the obligation — unlocks prepare — or dismiss as not_required with a REQUIRED assessment note; both are human-only CPA judgments that reject agent principals, design D5), assignee and notes. Writes a structured audit event capturing before/after.
Edit tracker metadata on one foreign-qualification row: the obligation assessment (confirm the obligation — unlocks prepare — or dismiss as not_required with a REQUIRED assessment note; both are human-only CPA judgments that reject agent principals, design D5), assignee and notes. Writes a structured audit event capturing before/after.
Request body ForeignQualificationUpdateForeignQualificationMetadataInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
foreignQualificationId | string | required | — |
obligationAssessment | enum: "confirmed" | "not_required" | optional | — |
assessmentNote | string | optional | — |
assignee | string | optional | — |
notes | string | optional | — |
reason | string | required | — |
Responses
- 200Successful invocation
ForeignQualificationUpdateForeignQualificationMetadataOutputField Type Required Description qualificationobjectrequired — changedFieldsarray<string>required — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/foreign-qualification.prepareForeignQualificationPopulate a foreign qualification's prepared form payload (officers, principal address, home-state formation details, the customer's OWN foreign-state registered agent — Kreto is not the RA — and the good-standing checklist) and transition pending/manual_required → prepared. APPROVAL_REQUIRED and UI-only. HARD GUARDS (design D5/D7): refused unless obligation_assessment='confirmed' (a human CPA judgment) and the catalog cell is at/above the display gate; a required good-standing certificate must be recorded as obtained. PII in form_payload is scrubbed from audit rows.
Populate a foreign qualification's prepared form payload (officers, principal address, home-state formation details, the customer's OWN foreign-state registered agent — Kreto is not the RA — and the good-standing checklist) and transition pending/manual_required → prepared. APPROVAL_REQUIRED and UI-only. HARD GUARDS (design D5/D7): refused unless obligation_assessment='confirmed' (a human CPA judgment) and the catalog cell is at/above the display gate; a required good-standing certificate must be recorded as obtained. PII in form_payload is scrubbed from audit rows.
Request body ForeignQualificationPrepareForeignQualificationInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
foreignQualificationId | string | required | — |
formPayload | object | required | — |
Responses
- 200Successful invocation
ForeignQualificationPrepareForeignQualificationOutputField Type Required Description qualificationobjectrequired — fromStatusenum: "pending" | "prepared" | "submitted" | "approved" | …required — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/foreign-qualification.requestForeignQualConciergeFilingRecord the '$149 File it for me' concierge request on a prepared foreign qualification: stamps filing_requested_at/by (design D3 — an annotation on 'prepared', not a status) and charges the $149 as a standalone Stripe invoice (created + finalized, so it bills every customer; owner 2026-07-10; fail-closed when STRIPE_SECRET_KEY is unset; double-bill safe). APPROVAL_REQUIRED: this moves money, so the v1 dispatcher blocks non-interactive API-key / MCP callers (KRT-1657) — it requires an interactive human session. Concierge gate (design D7): the catalog cell must be 'verified'. The click by an authenticated CPA/owner IS the recorded filing authorization. The state's own filing fee is separate and paid to the state.
Record the '$149 File it for me' concierge request on a prepared foreign qualification: stamps filing_requested_at/by (design D3 — an annotation on 'prepared', not a status) and charges the $149 as a standalone Stripe invoice (created + finalized, so it bills every customer; owner 2026-07-10; fail-closed when STRIPE_SECRET_KEY is unset; double-bill safe). APPROVAL_REQUIRED: this moves money, so the v1 dispatcher blocks non-interactive API-key / MCP callers (KRT-1657) — it requires an interactive human session. Concierge gate (design D7): the catalog cell must be 'verified'. The click by an authenticated CPA/owner IS the recorded filing authorization. The state's own filing fee is separate and paid to the state.
Request body ForeignQualificationRequestForeignQualConciergeFilingInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
foreignQualificationId | string | required | — |
Responses
- 200Successful invocation
ForeignQualificationRequestForeignQualConciergeFilingOutputField Type Required Description qualificationobjectrequired — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/foreign-qualification.transitionForeignQualificationStatusApply a matrix-gated status transition to a foreign-qualification tracker row (exact ear/esr 7-status machine). Supports the mark-filed extras (confirmationNumber + filedAt on → submitted), the approval record (qualificationDate + sosFileNumber on → approved — this becomes the authoritative annual-reports foreign anchor, design D9), the confirmedImmediately chain, and the manual withdrawal record (withdrawnAt on → expired; the sweep never writes expired). Every hop writes a hash-chained audit_events row.
Apply a matrix-gated status transition to a foreign-qualification tracker row (exact ear/esr 7-status machine). Supports the mark-filed extras (confirmationNumber + filedAt on → submitted), the approval record (qualificationDate + sosFileNumber on → approved — this becomes the authoritative annual-reports foreign anchor, design D9), the confirmedImmediately chain, and the manual withdrawal record (withdrawnAt on → expired; the sweep never writes expired). Every hop writes a hash-chained audit_events row.
Request body ForeignQualificationTransitionForeignQualificationStatusInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
foreignQualificationId | string | required | — |
newStatus | enum: "pending" | "prepared" | "submitted" | "approved" | … | required | — |
reason | string | required | — |
confirmationNumber | string | optional | — |
filedAt | string · date-time | optional | — |
qualificationDate | string | optional | — |
sosFileNumber | string | optional | — |
confirmedImmediately | boolean | optional | — |
withdrawnAt | string | optional | — |
lastError | string | optional | — |
Responses
- 200Successful invocation
ForeignQualificationTransitionForeignQualificationStatusOutputField Type Required Description qualificationobjectrequired — fromStatusenum: "pending" | "prepared" | "submitted" | "approved" | …required — toStatusenum: "pending" | "prepared" | "submitted" | "approved" | …required — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
l2:handbooks13
POST/v1/handbooks.listHandbookModulesList the handbook policy-module catalog (global config): per (jurisdiction × topic) modules with each module's CURRENT version and its per-version verification-ladder status, plus honest per-status counts. Assembly gate is verified-only (§0-1b): anything below 'verified' must never be rendered on a tenant surface as usable text.
List the handbook policy-module catalog (global config): per (jurisdiction × topic) modules with each module's CURRENT version and its per-version verification-ladder status, plus honest per-status counts. Assembly gate is verified-only (§0-1b): anything below 'verified' must never be rendered on a tenant surface as usable text.
Request body HandbooksListHandbookModulesInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
jurisdiction | string | optional | — |
category | enum: "federal_core" | "state_required" | "state_recommended" | optional | — |
verificationStatus | enum: "unverified" | "human_reviewed" | "verified" | optional | — |
Responses
- 200Successful invocation
HandbooksListHandbookModulesOutputField Type Required Description modulesarray<object>required — countsobjectrequired — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/handbooks.getHandbookModuleFetch one handbook policy module by (jurisdiction, topic) with its FULL version history (each version carries its own ladder status — verifying v3 says nothing about v4). Null module = no catalog coverage; the caller renders a coverage gap, never a blank.
Fetch one handbook policy module by (jurisdiction, topic) with its FULL version history (each version carries its own ladder status — verifying v3 says nothing about v4). Null module = no catalog coverage; the caller renders a coverage gap, never a blank.
Request body HandbooksGetHandbookModuleInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
jurisdiction | string | required | — |
topic | string | required | — |
Responses
- 200Successful invocation
HandbooksGetHandbookModuleOutputField Type Required Description moduleobjectrequired — versionsarray<object>required — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/handbooks.proposeHandbookModuleResearch-agent write path for the policy-module catalog. Creates the (jurisdiction, topic) module identity if missing and appends a NEW version row at verification_status='unverified' with mandatory provenance. NEVER touches an existing verified version (AC-22 clone) — a law change is a new version, promoted only by a human (AC-20 wall). Inputs are public (jurisdiction, topic) facts — PII-free by construction.
Research-agent write path for the policy-module catalog. Creates the (jurisdiction, topic) module identity if missing and appends a NEW version row at verification_status='unverified' with mandatory provenance. NEVER touches an existing verified version (AC-22 clone) — a law change is a new version, promoted only by a human (AC-20 wall). Inputs are public (jurisdiction, topic) facts — PII-free by construction.
Request body HandbooksProposeHandbookModuleInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
jurisdiction | string | required | — |
topic | string | required | — |
title | string | required | — |
category | enum: "federal_core" | "state_required" | "state_recommended" | required | — |
minEmployeeCount | integer | optional | — |
applicability | object | optional | — |
displayOrder | integer | optional | — |
bodyMd | string | required | — |
changeSummary | string | optional | — |
lawEffectiveDate | string | optional | — |
statuteCitations | array<object> | required | — |
draftedBy | enum: "research_agent" | "human" | optional | — |
draftProvenance | object | optional | — |
sourceUrl | string · uri | required | — |
retrievedAt | string · date-time | required | — |
notes | string | optional | — |
Responses
- 200Successful invocation
HandbooksProposeHandbookModuleOutputField Type Required Description moduleobjectrequired — versionobjectrequired — moduleCreatedbooleanrequired — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/handbooks.proposeStateRequiredTopicResearch-agent write path for the §3A2 completeness registry — which topics a state REQUIRES at what headcount (a fee-catalog-class checkable fact). Upserts one (jurisdiction, topic) row as 'unverified' with mandatory provenance. REFUSES to touch a row already at human_reviewed/verified (no-downgrade AC-22 clone). The §4 gap computation only trusts VERIFIED registry rows.
Research-agent write path for the §3A2 completeness registry — which topics a state REQUIRES at what headcount (a fee-catalog-class checkable fact). Upserts one (jurisdiction, topic) row as 'unverified' with mandatory provenance. REFUSES to touch a row already at human_reviewed/verified (no-downgrade AC-22 clone). The §4 gap computation only trusts VERIFIED registry rows.
Request body HandbooksProposeStateRequiredTopicInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
jurisdiction | string | required | — |
topic | string | required | — |
requirementKind | enum: "required" | "recommended" | required | — |
minEmployeeCount | integer | optional | — |
applicability | object | optional | — |
statuteCitations | array<object> | required | — |
sourceUrl | string · uri | required | — |
retrievedAt | string · date-time | required | — |
notes | string | optional | — |
Responses
- 200Successful invocation
HandbooksProposeStateRequiredTopicOutputField Type Required Description topicRowobjectrequired — createdbooleanrequired — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/handbooks.promoteHandbookModuleVersionPromote one policy-module VERSION along the verification ladder (unverified → human_reviewed → verified). APPROVAL_REQUIRED and UI-only: rejects any non-human principal (AC-20 wall), refuses missing source_url provenance. The promotion UI shows the §0-1(b) honest definition of what the click asserts. On 'verified': the prior verified version gets superseded_at and current_version_id advances (§7 step 3). 'human_reviewed' remains admin-queue-only — it renders on NO tenant surface (§0-1b).
Promote one policy-module VERSION along the verification ladder (unverified → human_reviewed → verified). APPROVAL_REQUIRED and UI-only: rejects any non-human principal (AC-20 wall), refuses missing source_url provenance. The promotion UI shows the §0-1(b) honest definition of what the click asserts. On 'verified': the prior verified version gets superseded_at and current_version_id advances (§7 step 3). 'human_reviewed' remains admin-queue-only — it renders on NO tenant surface (§0-1b).
Request body HandbooksPromoteHandbookModuleVersionInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
moduleVersionId | string | required | — |
targetStatus | enum: "human_reviewed" | "verified" | required | — |
reviewerEmail | string · email | required | — |
reason | string | required | — |
Responses
- 200Successful invocation
HandbooksPromoteHandbookModuleVersionOutputField Type Required Description versionobjectrequired — fromStatusenum: "unverified" | "human_reviewed" | "verified"required — toStatusenum: "unverified" | "human_reviewed" | "verified"required — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/handbooks.promoteStateRequiredTopicPromote a §3A2 completeness-registry row along the verification ladder. APPROVAL_REQUIRED and UI-only (AC-20 wall — rejects non-human principals; refuses missing source_url). Only VERIFIED registry rows feed the honest-gaps computation.
Promote a §3A2 completeness-registry row along the verification ladder. APPROVAL_REQUIRED and UI-only (AC-20 wall — rejects non-human principals; refuses missing source_url). Only VERIFIED registry rows feed the honest-gaps computation.
Request body HandbooksPromoteStateRequiredTopicInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
jurisdiction | string | required | — |
topic | string | required | — |
targetStatus | enum: "human_reviewed" | "verified" | required | — |
reviewerEmail | string · email | required | — |
reason | string | required | — |
Responses
- 200Successful invocation
HandbooksPromoteStateRequiredTopicOutputField Type Required Description topicRowobjectrequired — fromStatusenum: "unverified" | "human_reviewed" | "verified"required — toStatusenum: "unverified" | "human_reviewed" | "verified"required — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/handbooks.retireHandbookModuleVersionEMERGENCY version-level retire (§0-5d): a repealed/amended/enjoined statute pulls a verified version from assembly IMMEDIATELY, without waiting for a replacement to clear review — the ONE sanctioned exemption from no-downgrade. APPROVAL_REQUIRED, human-only, reason mandatory. Existing pins are unaffected (reconstructability holds) but published handbooks pinning this version get flagged by checkHandbookDrift.
EMERGENCY version-level retire (§0-5d): a repealed/amended/enjoined statute pulls a verified version from assembly IMMEDIATELY, without waiting for a replacement to clear review — the ONE sanctioned exemption from no-downgrade. APPROVAL_REQUIRED, human-only, reason mandatory. Existing pins are unaffected (reconstructability holds) but published handbooks pinning this version get flagged by checkHandbookDrift.
Request body HandbooksRetireHandbookModuleVersionInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
moduleVersionId | string | required | — |
reason | string | required | — |
Responses
- 200Successful invocation
HandbooksRetireHandbookModuleVersionOutputField Type Required Description versionobjectrequired — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/handbooks.listHandbooksList the tenant's handbook instances (per entity, versioned), filterable by entity and status. Paginated (default 25). Tenant-scoped via the invocation context.
List the tenant's handbook instances (per entity, versioned), filterable by entity and status. Paginated (default 25). Tenant-scoped via the invocation context.
Request body HandbooksListHandbooksInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
entityId | string | optional | — |
status | enum: "draft" | "published" | "superseded" | "archived" | optional | — |
limit | integer | optional | — |
offset | integer | optional | — |
Responses
- 200Successful invocation
HandbooksListHandbooksOutputField Type Required Description handbooksarray<object>required — totalnumberrequired — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/handbooks.generateHandbookDraftGenerate a handbook DRAFT for an entity: deterministic module selection (selectHandbookModules) from live operating states + per-state headcount, assembly gate = verified-only, honest coverage gaps computed against the §3A2 registry (uncovered states gap UNCONDITIONALLY), generation-time staleness warnings (§0-5c). Pins exact module-version ids. Publishing is a separate APPROVAL_REQUIRED step with the blocking disclaimer checkbox.
Generate a handbook DRAFT for an entity: deterministic module selection (selectHandbookModules) from live operating states + per-state headcount, assembly gate = verified-only, honest coverage gaps computed against the §3A2 registry (uncovered states gap UNCONDITIONALLY), generation-time staleness warnings (§0-5c). Pins exact module-version ids. Publishing is a separate APPROVAL_REQUIRED step with the blocking disclaimer checkbox.
Request body HandbooksGenerateHandbookDraftInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
entityId | string | required | — |
title | string | optional | — |
companyInputs | object | optional | — |
Responses
- 200Successful invocation
HandbooksGenerateHandbookDraftOutputField Type Required Description handbookobjectrequired — selectionobjectrequired — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/handbooks.publishHandbookPublish a draft handbook. APPROVAL_REQUIRED and UI-only: the §0-2(b) blocking disclaimer checkbox is part of the contract — refuses disclaimerAccepted !== true, stamps disclaimer_ack_at/by, records the exact checkbox copy in the hash-chained audit trail, freezes the pins + states_snapshot, supersedes the prior published version, and queues the PDF render (onboarding-docs queue posture — never a half-written published row).
Publish a draft handbook. APPROVAL_REQUIRED and UI-only: the §0-2(b) blocking disclaimer checkbox is part of the contract — refuses disclaimerAccepted !== true, stamps disclaimer_ack_at/by, records the exact checkbox copy in the hash-chained audit trail, freezes the pins + states_snapshot, supersedes the prior published version, and queues the PDF render (onboarding-docs queue posture — never a half-written published row).
Request body HandbooksPublishHandbookInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
handbookId | string | required | — |
disclaimerAccepted | boolean | required | — |
Responses
- 200Successful invocation
HandbooksPublishHandbookOutputField Type Required Description handbookobjectrequired — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/handbooks.sendHandbookAcknowledgmentsCreate one acknowledgment EVIDENCE row per active roster employee of the published handbook's entity — snapshotting name/email/work_state at send (§3E) — and email each a tokenized link (signature_requests clone). Employees without email land in an honest 'cannot reach' list. Idempotent: existing (handbook, employee) rows are skipped.
Create one acknowledgment EVIDENCE row per active roster employee of the published handbook's entity — snapshotting name/email/work_state at send (§3E) — and email each a tokenized link (signature_requests clone). Employees without email land in an honest 'cannot reach' list. Idempotent: existing (handbook, employee) rows are skipped.
Request body HandbooksSendHandbookAcknowledgmentsInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
handbookId | string | required | — |
Responses
- 200Successful invocation
HandbooksSendHandbookAcknowledgmentsOutputField Type Required Description creatednumberrequired — skippedExistingnumberrequired — cannotReacharray<object>required — emailFailuresnumberrequired — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/handbooks.getHandbookAckStatusThe acknowledgment tracking matrix for one handbook: per-employee sent/viewed/acknowledged status with honest counts. secure_token is never returned. Tenant-scoped.
The acknowledgment tracking matrix for one handbook: per-employee sent/viewed/acknowledged status with honest counts. secure_token is never returned. Tenant-scoped.
Request body HandbooksGetHandbookAckStatusInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
handbookId | string | required | — |
Responses
- 200Successful invocation
HandbooksGetHandbookAckStatusOutputField Type Required Description acksarray<object>required — countsobjectrequired — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/handbooks.checkHandbookDriftFlag every published handbook of an entity that is stale on either axis (§7 step 4): pinned-module drift (pins a superseded or emergency-retired version) or selection-input drift (a deterministic re-run of selectHandbookModules against LIVE operating states + headcount diverges from states_snapshot — new state registered, threshold crossed). Read-only; never auto-republishes (§0-5e).
Flag every published handbook of an entity that is stale on either axis (§7 step 4): pinned-module drift (pins a superseded or emergency-retired version) or selection-input drift (a deterministic re-run of selectHandbookModules against LIVE operating states + headcount diverges from states_snapshot — new state registered, threshold crossed). Read-only; never auto-republishes (§0-5e).
Request body HandbooksCheckHandbookDriftInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
entityId | string | required | — |
Responses
- 200Successful invocation
HandbooksCheckHandbookDriftOutputField Type Required Description entityIdstringrequired — flagsarray<object>required — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
l2:i9-records6
POST/v1/i9-records.createI9RecordCreate an I-9 record from Section 1 form data. SSN plaintext is encrypted via the public.app_create_secret vault wrapper; only the returned secret UUID is stored on the row. Dual-writes employees.i9_section1_complete = true. APPROVAL_REQUIRED.
Create an I-9 record from Section 1 form data. SSN plaintext is encrypted via the public.app_create_secret vault wrapper; only the returned secret UUID is stored on the row. Dual-writes employees.i9_section1_complete = true. APPROVAL_REQUIRED.
Request body I9RecordsCreateI9RecordInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
employeeId | string · uuid | required | — |
citizenshipStatus | enum: "us_citizen" | "noncitizen_national" | "lpr" | "authorized_alien" | required | — |
section1Data | object | required | — |
ssn | string | optional | — |
Responses
- 200Successful invocation
I9RecordsCreateI9RecordOutputField Type Required Description idstring · uuidrequired — tenant_idstring · uuidrequired — employee_idstring · uuidrequired — citizenship_statusenum: "us_citizen" | "noncitizen_national" | "lpr" | "authorized_alien" | …required — section1_completed_atstringrequired — section2_completed_atstringrequired — has_ssnbooleanrequired — ssn_last_4stringrequired — retention_untilstringrequired — is_archivedbooleanrequired — pdf_pathstringrequired — supporting_docs_pathsarray<string>required — created_atstringrequired — updated_atstringrequired — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/i9-records.getI9RecordFetch a single I-9 record by id, including decrypted SSN plaintext for the CPA detail view. APPROVAL_REQUIRED. The `ssn` field is redacted from audit outputs while the live caller receives the actual value (R13 mitigation, mirrors credential-vault.getCredential).
Fetch a single I-9 record by id, including decrypted SSN plaintext for the CPA detail view. APPROVAL_REQUIRED. The `ssn` field is redacted from audit outputs while the live caller receives the actual value (R13 mitigation, mirrors credential-vault.getCredential).
Request body I9RecordsGetI9RecordInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
i9RecordId | string · uuid | required | — |
Responses
- 200Successful invocation
I9RecordsGetI9RecordOutputField Type Required Description idstring · uuidrequired — tenant_idstring · uuidrequired — employee_idstring · uuidrequired — citizenship_statusenum: "us_citizen" | "noncitizen_national" | "lpr" | "authorized_alien" | …required — section1_completed_atstringrequired — section2_completed_atstringrequired — has_ssnbooleanrequired — ssn_last_4stringrequired — retention_untilstringrequired — is_archivedbooleanrequired — pdf_pathstringrequired — supporting_docs_pathsarray<string>required — created_atstringrequired — updated_atstringrequired — ssnstringrequired — section1_dataobjectrequired — section2_dataobjectrequired — list_a_docsarray<object>required — list_b_docsarray<object>required — list_c_docsarray<object>required — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/i9-records.updateI9RecordSection2Update an i9_record with Section 2 employer-review data. Validates Section 1 completion + USCIS document combination (List A XOR List B+C). Dual-writes employees.i9_section2_complete = true. APPROVAL_REQUIRED.
Update an i9_record with Section 2 employer-review data. Validates Section 1 completion + USCIS document combination (List A XOR List B+C). Dual-writes employees.i9_section2_complete = true. APPROVAL_REQUIRED.
Request body I9RecordsUpdateI9RecordSection2Inputrequired
| Field | Type | Required | Description |
|---|---|---|---|
i9RecordId | string · uuid | required | — |
section2Data | object | required | — |
reviewerUserId | string · uuid | optional | — |
Responses
- 200Successful invocation
I9RecordsUpdateI9RecordSection2OutputField Type Required Description idstring · uuidrequired — tenant_idstring · uuidrequired — employee_idstring · uuidrequired — citizenship_statusenum: "us_citizen" | "noncitizen_national" | "lpr" | "authorized_alien" | …required — section1_completed_atstringrequired — section2_completed_atstringrequired — has_ssnbooleanrequired — ssn_last_4stringrequired — retention_untilstringrequired — is_archivedbooleanrequired — pdf_pathstringrequired — supporting_docs_pathsarray<string>required — created_atstringrequired — updated_atstringrequired — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/i9-records.listI9RecordsList I-9 records in the caller's tenant. Returns metadata only (no plaintext SSN, no full section data). The `ssn_last_4` field is left null on this path — fetch via getI9Record for last-4 display. AUTONOMOUS.
List I-9 records in the caller's tenant. Returns metadata only (no plaintext SSN, no full section data). The `ssn_last_4` field is left null on this path — fetch via getI9Record for last-4 display. AUTONOMOUS.
Request body I9RecordsListI9RecordsInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
employeeId | string · uuid | optional | — |
includeArchived | boolean | optional | — |
Responses
- 200Successful invocation
I9RecordsListI9RecordsOutputField Type Required Description recordsarray<object>required — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/i9-records.addI9SupportingDocumentUpload a supporting document (passport image, driver's license, SSN card, etc.) for an I-9 record. Stores bytes in Supabase Storage cct-docs bucket under i9/<record-id>/list_<a|b|c>_doc_<n>.<ext> and appends the path to i9_records.supporting_docs_paths. APPROVAL_REQUIRED.
Upload a supporting document (passport image, driver's license, SSN card, etc.) for an I-9 record. Stores bytes in Supabase Storage cct-docs bucket under i9/<record-id>/list_<a|b|c>_doc_<n>.<ext> and appends the path to i9_records.supporting_docs_paths. APPROVAL_REQUIRED.
Request body I9RecordsAddI9SupportingDocumentInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
i9RecordId | string · uuid | required | — |
list | enum: "a" | "b" | "c" | required | — |
index | integer | required | — |
filename | string | required | — |
mimeType | string | required | — |
fileBytes | string · binary | required | — |
Responses
- 200Successful invocation
I9RecordsAddI9SupportingDocumentOutputField Type Required Description idstring · uuidrequired — tenant_idstring · uuidrequired — employee_idstring · uuidrequired — citizenship_statusenum: "us_citizen" | "noncitizen_national" | "lpr" | "authorized_alien" | …required — section1_completed_atstringrequired — section2_completed_atstringrequired — has_ssnbooleanrequired — ssn_last_4stringrequired — retention_untilstringrequired — is_archivedbooleanrequired — pdf_pathstringrequired — supporting_docs_pathsarray<string>required — created_atstringrequired — updated_atstringrequired — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/i9-records.generateI9PdfRender a USCIS Form I-9 PDF from i9_records data, store at cct-docs/i9/<id>/form.pdf, and update i9_records.pdf_path. Idempotent: subsequent calls overwrite the same path. SSN is decrypted internally and rendered into the PDF; never returned to the caller. APPROVAL_REQUIRED.
Render a USCIS Form I-9 PDF from i9_records data, store at cct-docs/i9/<id>/form.pdf, and update i9_records.pdf_path. Idempotent: subsequent calls overwrite the same path. SSN is decrypted internally and rendered into the PDF; never returned to the caller. APPROVAL_REQUIRED.
Request body I9RecordsGenerateI9PdfInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
i9RecordId | string · uuid | required | — |
Responses
- 200Successful invocation
I9RecordsGenerateI9PdfOutputField Type Required Description i9RecordIdstring · uuidrequired — pdf_pathstringrequired — byte_sizeintegerrequired — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
l2:location-detection4
POST/v1/location-detection.recordLocationChangeRecord a detected or operator-entered work-state transition for an employee. Idempotent on (employee_id, effective_date) — re-recording the same date returns the existing row's id with isDuplicate=true. NOTIFY — operator decision OR payroll-detection adapter call; the follow-up confirmLocationChange gates SUI/PFL jurisdiction routing.
Record a detected or operator-entered work-state transition for an employee. Idempotent on (employee_id, effective_date) — re-recording the same date returns the existing row's id with isDuplicate=true. NOTIFY — operator decision OR payroll-detection adapter call; the follow-up confirmLocationChange gates SUI/PFL jurisdiction routing.
Request body LocationDetectionRecordLocationChangeInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
employeeId | string · uuid | required | — |
toState | string | required | — |
fromState | string | optional | — |
effectiveDate | string | required | — |
source | enum: "payroll_detection" | "operator_manual" | "finch_sync" | "gusto_sync" | … | required | — |
metadata | object | optional | — |
Responses
- 200Successful invocation
LocationDetectionRecordLocationChangeOutputField Type Required Description idstring · uuidrequired — employeeIdstring · uuidrequired — toStatestringrequired — effectiveDatestringrequired — isDuplicatebooleanrequired — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/location-detection.listLocationChangesReturn tenant-scoped work-state transition history. Optional `entityId` / `employeeId` filters narrow the result; `onlyConfirmed` filters to operator-confirmed rows. Ordered most-recent effective_date first. AUTONOMOUS — read-only.
Return tenant-scoped work-state transition history. Optional `entityId` / `employeeId` filters narrow the result; `onlyConfirmed` filters to operator-confirmed rows. Ordered most-recent effective_date first. AUTONOMOUS — read-only.
Request body LocationDetectionListLocationChangesInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
entityId | string · uuid | optional | — |
employeeId | string · uuid | optional | — |
onlyConfirmed | boolean | optional | — |
limit | integer | optional | — |
Responses
- 200Successful invocation
LocationDetectionListLocationChangesOutputField Type Required Description changesarray<object>required — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/location-detection.confirmLocationChangeOperator confirms a detected work-state transition is real (not a payroll-data typo). Sets is_confirmed=true + confirmed_at + confirmed_by. Once confirmed, the locationDetection agent treats the row as the canonical state-of-record for the employee from effective_date forward. NOTIFY — operator override.
Operator confirms a detected work-state transition is real (not a payroll-data typo). Sets is_confirmed=true + confirmed_at + confirmed_by. Once confirmed, the locationDetection agent treats the row as the canonical state-of-record for the employee from effective_date forward. NOTIFY — operator override.
Request body LocationDetectionConfirmLocationChangeInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
id | string · uuid | required | — |
Responses
- 200Successful invocation
LocationDetectionConfirmLocationChangeOutputField Type Required Description idstring · uuidrequired — isConfirmedenum: truerequired — confirmedAtstringrequired — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/location-detection.getLatestLocationByEmployeeReturn the most recent confirmed work-state transition for an employee (as-of optional date; defaults to now). Returns {toState: null} when no confirmed rows exist. AUTONOMOUS — read-only.
Return the most recent confirmed work-state transition for an employee (as-of optional date; defaults to now). Returns {toState: null} when no confirmed rows exist. AUTONOMOUS — read-only.
Request body LocationDetectionGetLatestLocationByEmployeeInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
employeeId | string · uuid | required | — |
asOf | string | optional | — |
Responses
- 200Successful invocation
LocationDetectionGetLatestLocationByEmployeeOutputField Type Required Description employeeIdstring · uuidrequired — toStatestringrequired — effectiveDatestringrequired — isConfirmedbooleanrequired — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
l2:mailbox1
POST/v1/mailbox.listInboundList inbound mail for an employer entity. Returns received mail rows (newest first) with sender info, status, OCR text, and notice linkage. Tenant-scoped; RLS enforced with a defense-in-depth cross-tenant assertion. AUTONOMOUS — read-only, recoverable, no agency impact.
List inbound mail for an employer entity. Returns received mail rows (newest first) with sender info, status, OCR text, and notice linkage. Tenant-scoped; RLS enforced with a defense-in-depth cross-tenant assertion. AUTONOMOUS — read-only, recoverable, no agency impact.
Request body MailboxListInboundInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
entityId | string | required | — |
Responses
- 200Successful invocation
MailboxListInboundOutputField Type Required Description itemsarray<object>required — totalintegerrequired — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
l2:mfa7
POST/v1/mfa.getMatrixRead the Kreto-curated MFA capability row for a portal: supported second-factor methods, the preferred waterfall rung, whether the portal's identity layer blocks VoIP numbers, and the Google-Voice canary state. Use when enrolling a credential to pick the right MFA strategy for that portal.
Read the Kreto-curated MFA capability row for a portal: supported second-factor methods, the preferred waterfall rung, whether the portal's identity layer blocks VoIP numbers, and the Google-Voice canary state. Use when enrolling a credential to pick the right MFA strategy for that portal.
Request body MfaGetMatrixInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
agencyId | string | required | — |
Responses
- 200Successful invocation
MfaGetMatrixOutputField Type Required Description entryobjectrequired — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/mfa.resolveStrategyResolve which MFA rung the portal worker will drive for this account + portal: the account's per-portal override wins, else the curated matrix, else freeze_required (an unknown MFA method freezes the credential and requires a human — AC-13). A resolved 'sms' rung degrades to route_to_human while the relay is dormant.
Resolve which MFA rung the portal worker will drive for this account + portal: the account's per-portal override wins, else the curated matrix, else freeze_required (an unknown MFA method freezes the credential and requires a human — AC-13). A resolved 'sms' rung degrades to route_to_human while the relay is dormant.
Request body MfaResolveStrategyInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
agencyId | string | required | — |
Responses
- 200Successful invocation
MfaResolveStrategyOutputField Type Required Description strategyone of (enum: "totp" | "email" | "sms" | "route_to_human" | … · enum: "freeze_required")required — sourceenum: "override" | "matrix" | "unresolved"required — voipBlockedbooleanrequired — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/mfa.listHandoffsList the account's route-to-human MFA handoffs, newest first: any pending request (a portal session is waiting for a human to supply a code right now) plus the recent ledger (fulfilled / expired / escalated). Code values are never returned — codes are write-only.
List the account's route-to-human MFA handoffs, newest first: any pending request (a portal session is waiting for a human to supply a code right now) plus the recent ledger (fulfilled / expired / escalated). Code values are never returned — codes are write-only.
Request body MfaListHandoffsInputrequired
application/json
Responses
- 200Successful invocation
MfaListHandoffsOutputField Type Required Description handoffsarray<object>required — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/mfa.submitHandoffCodeSupply the MFA code a waiting portal session asked for (route-to-human). Fulfills the pending handoff so the portal worker can inject the code; refused once the session window has lapsed. UI-only.
Supply the MFA code a waiting portal session asked for (route-to-human). Fulfills the pending handoff so the portal worker can inject the code; refused once the session window has lapsed. UI-only.
Request body MfaSubmitHandoffCodeInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
handoffId | string | required | — |
code | string | required | — |
Responses
- 200Successful invocation
MfaSubmitHandoffCodeOutputField Type Required Description fulfilledbooleanrequired — windowLapsedbooleanrequired — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/mfa.listRelayNumbersList the account's leased receive-only relay numbers (one per credential, per the locked per-client model) and whether the SMS relay is currently enabled. Released numbers stay listed for the audit trail (AC-19).
List the account's leased receive-only relay numbers (one per credential, per the locked per-client model) and whether the SMS relay is currently enabled. Released numbers stay listed for the audit trail (AC-19).
Request body MfaListRelayNumbersInputrequired
application/json
Responses
- 200Successful invocation
MfaListRelayNumbersOutputField Type Required Description numbersarray<object>required — smsEnabledbooleanrequired — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/mfa.leaseRelayNumberLease a receive-only relay number for one credential (the SMS rung of the waterfall). Dormant: refuses with sms_disabled until OTP_SMS_ENABLED and a provider account exist. UI-only.
Lease a receive-only relay number for one credential (the SMS rung of the waterfall). Dormant: refuses with sms_disabled until OTP_SMS_ENABLED and a provider account exist. UI-only.
Request body MfaLeaseRelayNumberInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
credentialId | string | required | — |
Responses
- 200Successful invocation
MfaLeaseRelayNumberOutputField Type Required Description numberobjectrequired — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/mfa.releaseRelayNumberRelease a leased relay number (AC-19: credential revocation releases its relay number; the row is kept for the audit trail). UI-only.
Release a leased relay number (AC-19: credential revocation releases its relay number; the row is kept for the audit trail). UI-only.
Request body MfaReleaseRelayNumberInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
numberId | string | required | — |
Responses
- 200Successful invocation
MfaReleaseRelayNumberOutputField Type Required Description releasedbooleanrequired — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
l2:notice-intake14
POST/v1/notice-intake.uploadNoticeUpload a notice document to the notice intake pipeline. Computes SHA-256, uploads to Supabase Storage, INSERTs into notices, then fires runNoticePipeline() inline (fire-and-forget). AUTONOMOUS — recoverable; no agency impact at this stage.
Upload a notice document to the notice intake pipeline. Computes SHA-256, uploads to Supabase Storage, INSERTs into notices, then fires runNoticePipeline() inline (fire-and-forget). AUTONOMOUS — recoverable; no agency impact at this stage.
Request body NoticeIntakeUploadNoticeInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
fileBuffer | string · binary | required | — |
fileName | string | required | — |
contentType | string | required | — |
source | enum: "cpa_upload" | "employer_upload" | "email_intake" | "mail_scan" | … | required | — |
entityId | string | optional | — |
sourceVendorDocId | string | optional | — |
parentNoticeId | string | optional | — |
Responses
- 200Successful invocation
NoticeIntakeUploadNoticeOutputField Type Required Description noticeIdstringrequired — documentIdstringrequired — storagePathstringrequired — contentHashstringrequired — pipelineEnqueuedbooleanrequired — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/notice-intake.ingestEmailWrap the existing /api/webhooks/inbound-email logic into a typed service method. Slug-based routing → domain fallback → unmatched queue. AUTONOMOUS — system-driven, idempotent at the inbound_emails row level.
Wrap the existing /api/webhooks/inbound-email logic into a typed service method. Slug-based routing → domain fallback → unmatched queue. AUTONOMOUS — system-driven, idempotent at the inbound_emails row level.
Request body NoticeIntakeIngestEmailInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
resendPayload | object | required | — |
Responses
- 200Successful invocation
NoticeIntakeIngestEmailOutputField Type Required Description inboundEmailIdstringrequired — matchMethodenum: "slug" | "domain" | "none"required — matchedTenantIdstringrequired — matchedEntityIdstringrequired — unmatchedbooleanrequired — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/notice-intake.classifyNoticeWrap agentClassify with a typed service-method surface. Reads the notice's raw_text + state, calls the LLM classifier, persists notice_type_classified + classification_confidence + notice_facts. AUTONOMOUS — read-modify, recoverable.
Wrap agentClassify with a typed service-method surface. Reads the notice's raw_text + state, calls the LLM classifier, persists notice_type_classified + classification_confidence + notice_facts. AUTONOMOUS — read-modify, recoverable.
Request body NoticeIntakeClassifyNoticeInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
noticeId | string | required | — |
Responses
- 200Successful invocation
NoticeIntakeClassifyNoticeOutputField Type Required Description noticeIdstringrequired — noticeTypestringrequired — confidencenumberrequired — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/notice-intake.ingestNoticeWrap agentIngest with a typed service-method surface. Runs OCR / text-extraction (Google Document AI -> Claude Vision fallback) + SHA-256 dedup, persists raw_text + sha256_hash + pipeline_status. AUTONOMOUS — read-modify, recoverable.
Wrap agentIngest with a typed service-method surface. Runs OCR / text-extraction (Google Document AI -> Claude Vision fallback) + SHA-256 dedup, persists raw_text + sha256_hash + pipeline_status. AUTONOMOUS — read-modify, recoverable.
Request body NoticeIntakeIngestNoticeInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
noticeId | string | required | — |
Responses
- 200Successful invocation
NoticeIntakeIngestNoticeOutputField Type Required Description noticeIdstringrequired — pipelineStatusstringrequired — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/notice-intake.validateNoticeWrap agentValidate with a typed service-method surface. Runs SUI / rate verification + payroll cross-reference, flags protest + potential savings, persists pipeline_status + protest_recommended. AUTONOMOUS — read-modify, recoverable.
Wrap agentValidate with a typed service-method surface. Runs SUI / rate verification + payroll cross-reference, flags protest + potential savings, persists pipeline_status + protest_recommended. AUTONOMOUS — read-modify, recoverable.
Request body NoticeIntakeValidateNoticeInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
noticeId | string | required | — |
Responses
- 200Successful invocation
NoticeIntakeValidateNoticeOutputField Type Required Description noticeIdstringrequired — pipelineStatusstringrequired — protestRecommendedbooleanrequired — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/notice-intake.setNoticeDeadlineWrap agentDeadline with a typed service-method surface. Computes the response deadline + protest clock from the notice's classification + per-state rules, persists deadline + protest_deadline + pipeline_status. AUTONOMOUS — read-modify, recoverable.
Wrap agentDeadline with a typed service-method surface. Computes the response deadline + protest clock from the notice's classification + per-state rules, persists deadline + protest_deadline + pipeline_status. AUTONOMOUS — read-modify, recoverable.
Request body NoticeIntakeSetNoticeDeadlineInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
noticeId | string | required | — |
Responses
- 200Successful invocation
NoticeIntakeSetNoticeDeadlineOutputField Type Required Description noticeIdstringrequired — pipelineStatusstringrequired — deadlinestringrequired — protestDeadlinestringrequired — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/notice-intake.reclassifyNoticeOperator-driven re-classification. Re-runs the classifier AND cascades to downstream agents (validate, deadline, draft). NOTIFY — operator override, audit-visible. Reason field NOT redacted (operator-authored; if PII leaks, it's the operator's responsibility — flagged in README).
Operator-driven re-classification. Re-runs the classifier AND cascades to downstream agents (validate, deadline, draft). NOTIFY — operator override, audit-visible. Reason field NOT redacted (operator-authored; if PII leaks, it's the operator's responsibility — flagged in README).
Request body NoticeIntakeReclassifyNoticeInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
noticeId | string | required | — |
reason | string | required | — |
Responses
- 200Successful invocation
NoticeIntakeReclassifyNoticeOutputField Type Required Description noticeIdstringrequired — noticeTypestringrequired — confidencenumberrequired — cascadedAgentsarray<string>required — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/notice-intake.routeNoticeAssign a notice to an employer entity. Mirrors entity-match-resolve route's 'confirmed' action. Pure data update — does NOT advance pipeline_status, does NOT cascade to downstream agents. NOTIFY — operator override, audit-visible.
Assign a notice to an employer entity. Mirrors entity-match-resolve route's 'confirmed' action. Pure data update — does NOT advance pipeline_status, does NOT cascade to downstream agents. NOTIFY — operator override, audit-visible.
Request body NoticeIntakeRouteNoticeInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
noticeId | string | required | — |
entityId | string | required | — |
Responses
- 200Successful invocation
NoticeIntakeRouteNoticeOutputField Type Required Description noticeIdstringrequired — previousEntityIdstringrequired — newEntityIdstringrequired — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/notice-intake.flagJunkMark a notice as junk. Sets is_junk=true + pipeline_status=DISMISSED. NOTIFY — recoverable (operator can unflag); no compliance impact from a wrong call. Compliance-impact gate is at submitProtest (Phase 3).
Mark a notice as junk. Sets is_junk=true + pipeline_status=DISMISSED. NOTIFY — recoverable (operator can unflag); no compliance impact from a wrong call. Compliance-impact gate is at submitProtest (Phase 3).
Request body NoticeIntakeFlagJunkInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
noticeId | string | required | — |
reason | enum: "marketing" | "portal_automation" | "bounce_notification" | "newsletter" | … | required | — |
reasonDetail | string | optional | — |
Responses
- 200Successful invocation
NoticeIntakeFlagJunkOutputField Type Required Description noticeIdstringrequired — isJunkenum: truerequired — pipelineStatusenum: "DISMISSED"required — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/notice-intake.unflagJunkReverse a junk flag. Sets is_junk=false + pipeline_status=PENDING so the normal pipeline can re-run. NOTIFY — operator override; the reason field is the operator's audit-rationale (10–500 chars).
Reverse a junk flag. Sets is_junk=false + pipeline_status=PENDING so the normal pipeline can re-run. NOTIFY — operator override; the reason field is the operator's audit-rationale (10–500 chars).
Request body NoticeIntakeUnflagJunkInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
noticeId | string | required | — |
reason | string | required | — |
Responses
- 200Successful invocation
NoticeIntakeUnflagJunkOutputField Type Required Description noticeIdstringrequired — isJunkenum: falserequired — pipelineStatusenum: "PENDING"required — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/notice-intake.draftNoticeWrap agentDraft with a typed service-method surface. Generates the protest-letter draft for the notice (persists `protest_draft` + `protest_draft_generated_at` + `pipeline_status='READY_FOR_REVIEW'`) and returns a typed acknowledgment. NOTIFY — read-modify, a human reviews the draft before any external send.
Wrap agentDraft with a typed service-method surface. Generates the protest-letter draft for the notice (persists `protest_draft` + `protest_draft_generated_at` + `pipeline_status='READY_FOR_REVIEW'`) and returns a typed acknowledgment. NOTIFY — read-modify, a human reviews the draft before any external send.
Request body NoticeIntakeDraftNoticeInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
noticeId | string | required | — |
Responses
- 200Successful invocation
NoticeIntakeDraftNoticeOutputField Type Required Description noticeIdstringrequired — hasDraftbooleanrequired — draftLengthintegerrequired — pipelineStatusstringrequired — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/notice-intake.approveNoticeOperator marks the generated draft as approved + ready to file. Records approved_at + approved_by + cpa_action='approved'. Does NOT transition pipeline_status or send anything externally. NOTIFY — reversible; fileNotice is the external-impact gate.
Operator marks the generated draft as approved + ready to file. Records approved_at + approved_by + cpa_action='approved'. Does NOT transition pipeline_status or send anything externally. NOTIFY — reversible; fileNotice is the external-impact gate.
Request body NoticeIntakeApproveNoticeInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
noticeId | string | required | — |
note | string | optional | — |
Responses
- 200Successful invocation
NoticeIntakeApproveNoticeOutputField Type Required Description noticeIdstringrequired — approvedAtstringrequired — cpaActionenum: "approved"required — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/notice-intake.fileNoticeOperator records that the approved response has been transmitted to the agency. Stores filed_at + filed_by + filing_method, advances pipeline_status to ACTIONED. Requires cpa_action='approved' (the approve-before-file invariant). NOTIFY — records external act; Kreto itself does NOT mail/fax/post in this op.
Operator records that the approved response has been transmitted to the agency. Stores filed_at + filed_by + filing_method, advances pipeline_status to ACTIONED. Requires cpa_action='approved' (the approve-before-file invariant). NOTIFY — records external act; Kreto itself does NOT mail/fax/post in this op.
Request body NoticeIntakeFileNoticeInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
noticeId | string | required | — |
filingMethod | enum: "mail" | "fax" | "online_portal" | "email" | … | required | — |
note | string | optional | — |
Responses
- 200Successful invocation
NoticeIntakeFileNoticeOutputField Type Required Description noticeIdstringrequired — filedAtstringrequired — filingMethodenum: "mail" | "fax" | "online_portal" | "email" | …required — pipelineStatusenum: "ACTIONED"required — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/notice-intake.escalateNoticeFlag a notice for senior-CPA review. Sets is_escalated=true + escalated_at + escalated_by + escalation_reason. Does NOT change pipeline_status (escalation is orthogonal). Idempotent — re-calling updates the reason + timestamp. NOTIFY — flag-only; no external impact.
Flag a notice for senior-CPA review. Sets is_escalated=true + escalated_at + escalated_by + escalation_reason. Does NOT change pipeline_status (escalation is orthogonal). Idempotent — re-calling updates the reason + timestamp. NOTIFY — flag-only; no external impact.
Request body NoticeIntakeEscalateNoticeInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
noticeId | string | required | — |
reason | string | required | — |
Responses
- 200Successful invocation
NoticeIntakeEscalateNoticeOutputField Type Required Description noticeIdstringrequired — isEscalatedenum: truerequired — escalatedAtstringrequired — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
l2:notices4
POST/v1/notices.submitDraftFeedbackRecord thumbs-up/down feedback on a notice response draft. Asserts the notice and draft both belong to the caller's tenant, inserts a draft_feedback row, and emits a product-analytics event. NOTIFY — operator-driven, audit-visible.
Record thumbs-up/down feedback on a notice response draft. Asserts the notice and draft both belong to the caller's tenant, inserts a draft_feedback row, and emits a product-analytics event. NOTIFY — operator-driven, audit-visible.
Request body NoticesSubmitDraftFeedbackInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
noticeId | string | required | — |
draftId | string | required | — |
rating | enum: "thumbs_up" | "thumbs_down" | required | — |
comment | string | optional | — |
Responses
- 200Successful invocation
NoticesSubmitDraftFeedbackOutputField Type Required Description successenum: truerequired — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/notices.resolveEntityMatchResolve a notice's fuzzy entity match: confirm an existing entity, or create a new entity under the notice's tenant and assign it. Tenant-scoped with defense-in-depth assertions. NOTIFY — operator-driven, audit-visible.
Resolve a notice's fuzzy entity match: confirm an existing entity, or create a new entity under the notice's tenant and assign it. Tenant-scoped with defense-in-depth assertions. NOTIFY — operator-driven, audit-visible.
Request body NoticesResolveEntityMatchInputrequired
application/json
Responses
- 200Successful invocation
NoticesResolveEntityMatchOutputField Type Required Description successenum: truerequired — entityIdstringrequired — actionenum: "confirmed" | "create_new"required — entityNamestringoptional — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/notices.linkLink an agency-response notice to its parent (original) notice and record the response type (acceptance/counter/additional_info_request/rejection). Sets parent_notice_id + agency_response_type on the response notice. Both notices must belong to the caller's tenant. AUTONOMOUS — internal edge write, recoverable, no agency impact.
Link an agency-response notice to its parent (original) notice and record the response type (acceptance/counter/additional_info_request/rejection). Sets parent_notice_id + agency_response_type on the response notice. Both notices must belong to the caller's tenant. AUTONOMOUS — internal edge write, recoverable, no agency impact.
Request body NoticesLinkInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
noticeId | string | required | — |
parentNoticeId | string | required | — |
agencyResponseType | enum: "acceptance" | "counter" | "additional_info_request" | "rejection" | required | — |
Responses
- 200Successful invocation
NoticesLinkOutputField Type Required Description successenum: truerequired — noticeIdstringrequired — parentNoticeIdstringrequired — agencyResponseTypeenum: "acceptance" | "counter" | "additional_info_request" | "rejection"required — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/notices.deadlineSweepPreview the deadline escalations that would fire for your tenant — which compliance-notice deadlines are escalating and who would be notified. Read-only plan over the same ladder + candidate filter the hourly cron uses; sends nothing and writes nothing (the cron does the actual emails/push/Slack). Use to surface what deadlines need attention now. NOTIFY — surfaces work for human attention, no external impact.
Preview the deadline escalations that would fire for your tenant — which compliance-notice deadlines are escalating and who would be notified. Read-only plan over the same ladder + candidate filter the hourly cron uses; sends nothing and writes nothing (the cron does the actual emails/push/Slack). Use to surface what deadlines need attention now. NOTIFY — surfaces work for human attention, no external impact.
Request body NoticesDeadlineSweepInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
entityId | string | optional | — |
horizonDays | integer | optional | — |
Responses
- 200Successful invocation
NoticesDeadlineSweepOutputField Type Required Description asOfstringrequired — scannedNoticesintegerrequired — escalationsarray<object>required — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
l2:notifications2
POST/v1/notifications.listList the account's vault notifications, newest first: pending time-critical items (awaiting a human acknowledgement) and the informational ledger (rotations completed, credentials frozen, health changes). Content is reference-and-action only — never a secret, code, or amount.
List the account's vault notifications, newest first: pending time-critical items (awaiting a human acknowledgement) and the informational ledger (rotations completed, credentials frozen, health changes). Content is reference-and-action only — never a secret, code, or amount.
Request body NotificationsListInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
status | enum: "pending" | "acknowledged" | "expired" | optional | — |
Responses
- 200Successful invocation
NotificationsListOutputField Type Required Description notificationsarray<object>required — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/notifications.ackAcknowledge a time-critical notification, stopping its escalation. Escalate-until-ack means until a HUMAN acks — UI-only by design.
Acknowledge a time-critical notification, stopping its escalation. Escalate-until-ack means until a HUMAN acks — UI-only by design.
Request body NotificationsAckInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
notificationId | string | required | — |
Responses
- 200Successful invocation
NotificationsAckOutputField Type Required Description acknowledgedbooleanrequired — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
l2:payments5
POST/v1/payments.remitRequest a payment from a stored payment/bank credential. Creates an approval request ONLY — money never moves without a human approving this exact request (the hard floor no configuration can relax). The responsible humans are notified WITHOUT the amount; they first see the figure on the approval screen.
Request a payment from a stored payment/bank credential. Creates an approval request ONLY — money never moves without a human approving this exact request (the hard floor no configuration can relax). The responsible humans are notified WITHOUT the amount; they first see the figure on the approval screen.
Request body PaymentsRemitInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
credentialId | string | required | — |
payee | string | required | — |
amountCents | integer | required | — |
currency | string | optional | — |
memo | string | optional | — |
Responses
- 200Successful invocation
PaymentsRemitOutputField Type Required Description requestobjectrequired — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/payments.listList the account's payment approval requests, newest first. Use to surface what is awaiting human approval; approving is UI-only.
List the account's payment approval requests, newest first. Use to surface what is awaiting human approval; approving is UI-only.
Request body PaymentsListInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
status | enum: "requested" | "approved" | "rejected" | "expired" | optional | — |
Responses
- 200Successful invocation
PaymentsListOutputField Type Required Description requestsarray<object>required — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/payments.approveApprove a pending payment request — the money-movement hard floor. Requires a human actor and a typed amount that matches the request exactly; the approval (approver identity + amount) is sealed into the tamper-evident audit chain and becomes the authorization. UI-only; no configuration can bypass this step.
Approve a pending payment request — the money-movement hard floor. Requires a human actor and a typed amount that matches the request exactly; the approval (approver identity + amount) is sealed into the tamper-evident audit chain and becomes the authorization. UI-only; no configuration can bypass this step.
Request body PaymentsApproveInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
approvalId | string | required | — |
confirmAmountCents | integer | required | — |
Responses
- 200Successful invocation
PaymentsApproveOutputField Type Required Description requestobjectrequired — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/payments.rejectReject a pending payment request. The rejection is recorded on the audit chain. UI-only.
Reject a pending payment request. The rejection is recorded on the audit chain. UI-only.
Request body PaymentsRejectInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
approvalId | string | required | — |
Responses
- 200Successful invocation
PaymentsRejectOutputField Type Required Description requestobjectrequired — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/payments.executeExecute an APPROVED payment. DORMANT: Kreto has no payment rails — this refuses payment_rails_unavailable for every request, approved or not. When an ACH/provider integration lands it slots in here; the approval floor above it does not change. UI-only.
Execute an APPROVED payment. DORMANT: Kreto has no payment rails — this refuses payment_rails_unavailable for every request, approved or not. When an ACH/provider integration lands it slots in here; the approval floor above it does not change. UI-only.
Request body PaymentsExecuteInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
approvalId | string | required | — |
Responses
- 200Successful invocation
PaymentsExecuteOutputField Type Required Description executedenum: falserequired — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
l2:payroll1
POST/v1/payroll.connectInitiate a payroll connection for an entity. Returns 'connected' (already linked), 'consent_required' (the employer must accept the KRT-768 consent in the UI first — never recorded on their behalf), or 'pending' (consent present; a pending connection intent is recorded and the employer completes the provider OAuth in the UI). Use to unblock a notice that needs payroll. NOTIFY — records the intent; the actual link is the employer's OAuth action.
Initiate a payroll connection for an entity. Returns 'connected' (already linked), 'consent_required' (the employer must accept the KRT-768 consent in the UI first — never recorded on their behalf), or 'pending' (consent present; a pending connection intent is recorded and the employer completes the provider OAuth in the UI). Use to unblock a notice that needs payroll. NOTIFY — records the intent; the actual link is the employer's OAuth action.
Request body PayrollConnectInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
entityId | string | required | — |
provider | enum: "gusto" | "adp_run" | "paychex" | "paylocity" | … | required | — |
Responses
- 200Successful invocation
PayrollConnectOutputField Type Required Description entityIdstringrequired — providerenum: "gusto" | "adp_run" | "paychex" | "paylocity" | …required — statusenum: "connected" | "consent_required" | "pending"required — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
l2:peo7
POST/v1/peo.listEmployersList the PEO tenant's managed employer book with per-employer compliance rollups: open-notice count, obligations due within 30 days, state registrations in flight, compliance score, declared employee count, and PEPM subscription status. Paginated via `page` (1-indexed) and `pageSize` (1-50, default 12). Optional `filter` (all | attention | registrations_in_flight | no_subscription), case-insensitive `search` on legal name, and `sort` (name | score | open_notices). Tenant-scoped. Returns aggregates + business identifiers only — no PII (EIN as last-4 only, no contact fields). Requires the ENABLE_PEO_PORTAL flag; refuses with FEATURE_DISABLED when off.
List the PEO tenant's managed employer book with per-employer compliance rollups: open-notice count, obligations due within 30 days, state registrations in flight, compliance score, declared employee count, and PEPM subscription status. Paginated via `page` (1-indexed) and `pageSize` (1-50, default 12). Optional `filter` (all | attention | registrations_in_flight | no_subscription), case-insensitive `search` on legal name, and `sort` (name | score | open_notices). Tenant-scoped. Returns aggregates + business identifiers only — no PII (EIN as last-4 only, no contact fields). Requires the ENABLE_PEO_PORTAL flag; refuses with FEATURE_DISABLED when off.
Request body PeoListEmployersInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
page | integer | optional | — |
pageSize | integer | optional | — |
filter | enum: "all" | "attention" | "registrations_in_flight" | "no_subscription" | optional | — |
search | string | optional | — |
sort | enum: "name" | "score" | "open_notices" | optional | — |
Responses
- 200Successful invocation
PeoListEmployersOutputField Type Required Description employersarray<object>required — totalintegerrequired — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/peo.getPortfolioSummaryBook-level compliance + billing summary for the PEO tenant: employer count, total open notices, state registrations in flight, obligations due within 30 days, the top-5 at-risk employers by ascending compliance score, and the estimated monthly PEPM total (estimate at the live per-entity rate — read-only, no Stripe interaction). Takes no input. Tenant-scoped; returns aggregates + business identifiers only, no PII. Requires the ENABLE_PEO_PORTAL flag; refuses with FEATURE_DISABLED when off.
Book-level compliance + billing summary for the PEO tenant: employer count, total open notices, state registrations in flight, obligations due within 30 days, the top-5 at-risk employers by ascending compliance score, and the estimated monthly PEPM total (estimate at the live per-entity rate — read-only, no Stripe interaction). Takes no input. Tenant-scoped; returns aggregates + business identifiers only, no PII. Requires the ENABLE_PEO_PORTAL flag; refuses with FEATURE_DISABLED when off.
Request body PeoGetPortfolioSummaryInputrequired
application/json
Responses
- 200Successful invocation
PeoGetPortfolioSummaryOutputField Type Required Description employerCountintegerrequired — openNoticesintegerrequired — registrationsInFlightintegerrequired — obligationsDue30integerrequired — atRiskarray<object>required — estimatedMonthlyPepmUsdnumberrequired — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/peo.getBillingRollupRead-only aggregate PEPM billing view over the PEO tenant's employer book: one row per employer with the resolved billing quantity (via the live source-priority chain: payroll > declared > employees), quantity source, subscription status, estimated monthly cost at the current per-entity rate, and whether a Stripe customer-portal link is available — plus book-wide totals (billable employees, estimated monthly total, subscribed count, and how many employers were excluded as unresolvable). All figures are ESTIMATES; this method never creates or mutates any Stripe object. Paginated via `page` / `pageSize` (1-50, default 12). Requires the ENABLE_PEO_PORTAL flag; refuses with FEATURE_DISABLED when off.
Read-only aggregate PEPM billing view over the PEO tenant's employer book: one row per employer with the resolved billing quantity (via the live source-priority chain: payroll > declared > employees), quantity source, subscription status, estimated monthly cost at the current per-entity rate, and whether a Stripe customer-portal link is available — plus book-wide totals (billable employees, estimated monthly total, subscribed count, and how many employers were excluded as unresolvable). All figures are ESTIMATES; this method never creates or mutates any Stripe object. Paginated via `page` / `pageSize` (1-50, default 12). Requires the ENABLE_PEO_PORTAL flag; refuses with FEATURE_DISABLED when off.
Request body PeoGetBillingRollupInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
page | integer | optional | — |
pageSize | integer | optional | — |
Responses
- 200Successful invocation
PeoGetBillingRollupOutputField Type Required Description rowsarray<object>required — totalintegerrequired — totalsobjectrequired — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/peo.addEmployerAdd a single managed employer to the PEO tenant's book. Creates an entities row (legal name, primary state, optional EIN — persisted as last-4 only — contact fields, declared employee count) plus the hash-chained audit event, reusing the standard employer-creation path. Refuses with DUPLICATE_EMPLOYER (409) when an employer with the same normalized legal name + primary state already exists. Requires the ENABLE_PEO_PORTAL flag; refuses with FEATURE_DISABLED when off.
Add a single managed employer to the PEO tenant's book. Creates an entities row (legal name, primary state, optional EIN — persisted as last-4 only — contact fields, declared employee count) plus the hash-chained audit event, reusing the standard employer-creation path. Refuses with DUPLICATE_EMPLOYER (409) when an employer with the same normalized legal name + primary state already exists. Requires the ENABLE_PEO_PORTAL flag; refuses with FEATURE_DISABLED when off.
Request body PeoAddEmployerInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
legalName | string | required | — |
primaryState | string | required | — |
ein | string | optional | — |
contactName | string | optional | — |
contactEmail | string · email | optional | — |
declaredEmployeeCount | integer | optional | — |
Responses
- 200Successful invocation
PeoAddEmployerOutputField Type Required Description entityIdstringrequired — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/peo.validateEmployerImportValidate and stage an employer-book CSV for the PEO tenant. Parses the CSV server-side (columns: legal_name*, primary_state*, ein, contact_name, contact_email, declared_employee_count; 2 MB / 2,000 row caps), normalizes every row, reduces any full EIN to its last 4 digits, detects duplicates against both existing employers and other rows in the same file, and stages every row with a per-row verdict (valid | error | duplicate) plus machine-readable reasons. Returns the staged import id and verdict counts. STAGING ONLY — never creates employers; a human must review and commit the staged import from the portal. Refuses with IMPORT_TOO_LARGE (400) over the caps, VALIDATION_FAILED (422) for an unparseable file or broken header, and FEATURE_DISABLED (403) when the ENABLE_PEO_PORTAL flag is off.
Validate and stage an employer-book CSV for the PEO tenant. Parses the CSV server-side (columns: legal_name*, primary_state*, ein, contact_name, contact_email, declared_employee_count; 2 MB / 2,000 row caps), normalizes every row, reduces any full EIN to its last 4 digits, detects duplicates against both existing employers and other rows in the same file, and stages every row with a per-row verdict (valid | error | duplicate) plus machine-readable reasons. Returns the staged import id and verdict counts. STAGING ONLY — never creates employers; a human must review and commit the staged import from the portal. Refuses with IMPORT_TOO_LARGE (400) over the caps, VALIDATION_FAILED (422) for an unparseable file or broken header, and FEATURE_DISABLED (403) when the ENABLE_PEO_PORTAL flag is off.
Request body PeoValidateEmployerImportInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
filename | string | required | — |
csvText | string | required | — |
Responses
- 200Successful invocation
PeoValidateEmployerImportOutputField Type Required Description importIdstringrequired — rowCountintegerrequired — validCountintegerrequired — errorCountintegerrequired — duplicateCountintegerrequired — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/peo.getImportRead a staged employer-CSV import: the summary (filename, lifecycle status, row/valid/error/duplicate counts, committed-at) plus the staged rows with per-row verdicts (valid | error | duplicate), machine-readable reasons, and — after a commit — the created entity id or per-row commit error. Feeds the import wizard's review and commit-progress screens. Paginated via `page` / `pageSize` (1-2,000, default 2,000 — one page covers a whole v1 import). Tenant-scoped; returns business identifiers only (EIN as last-4, no contact fields). Refuses with IMPORT_NOT_FOUND (404) for unknown or other-tenant imports and FEATURE_DISABLED (403) when the ENABLE_PEO_PORTAL flag is off.
Read a staged employer-CSV import: the summary (filename, lifecycle status, row/valid/error/duplicate counts, committed-at) plus the staged rows with per-row verdicts (valid | error | duplicate), machine-readable reasons, and — after a commit — the created entity id or per-row commit error. Feeds the import wizard's review and commit-progress screens. Paginated via `page` / `pageSize` (1-2,000, default 2,000 — one page covers a whole v1 import). Tenant-scoped; returns business identifiers only (EIN as last-4, no contact fields). Refuses with IMPORT_NOT_FOUND (404) for unknown or other-tenant imports and FEATURE_DISABLED (403) when the ENABLE_PEO_PORTAL flag is off.
Request body PeoGetImportInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
importId | string | required | — |
page | integer | optional | — |
pageSize | integer | optional | — |
Responses
- 200Successful invocation
PeoGetImportOutputField Type Required Description importobjectrequired — rowsarray<object>required — rowTotalintegerrequired — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/peo.commitEmployerImportCommit a staged employer-CSV import — the HUMAN approval gate of the bulk-import pipeline. Verifies the import belongs to the tenant and is committable (status 'staged', or 'failed' to resume a partial failure), flips it to 'committing', and enqueues the idempotent peo_import_commit worker job that creates one employer (entities row) per valid staged row with hash-chained audit evidence. Returns the job id; poll peo.getImport for per-row progress. Session-only: APPROVAL_REQUIRED risk level (excluded from MCP/CLI; the API dispatcher refuses non-session callers) and the handler rejects any non-user actor. Refuses with IMPORT_NOT_STAGED (409) for non-committable states, IMPORT_NOT_FOUND (404) for unknown or other-tenant imports, and FEATURE_DISABLED (403) when the ENABLE_PEO_PORTAL flag is off.
Commit a staged employer-CSV import — the HUMAN approval gate of the bulk-import pipeline. Verifies the import belongs to the tenant and is committable (status 'staged', or 'failed' to resume a partial failure), flips it to 'committing', and enqueues the idempotent peo_import_commit worker job that creates one employer (entities row) per valid staged row with hash-chained audit evidence. Returns the job id; poll peo.getImport for per-row progress. Session-only: APPROVAL_REQUIRED risk level (excluded from MCP/CLI; the API dispatcher refuses non-session callers) and the handler rejects any non-user actor. Refuses with IMPORT_NOT_STAGED (409) for non-committable states, IMPORT_NOT_FOUND (404) for unknown or other-tenant imports, and FEATURE_DISABLED (403) when the ENABLE_PEO_PORTAL flag is off.
Request body PeoCommitEmployerImportInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
importId | string | required | — |
Responses
- 200Successful invocation
PeoCommitEmployerImportOutputField Type Required Description jobIdstringrequired — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
l2:poa-filing3
POST/v1/poa-filing.generate8821Generate an IRS Form 8821 (Tax Information Authorization) naming Kreto Inc. as the taxpayer's information designee. Fills the official IRS PDF template with the taxpayer's entity data and selected tax matters / years, uploads the unsigned PDF to Supabase Storage, creates a draft poa_authorizations row and a signature_requests row, returns the signing URL. The taxpayer (authorized signer on the entity) signs via the existing signing flow; finalization writes the signed PDF URL back to the poa_authorizations row.
Generate an IRS Form 8821 (Tax Information Authorization) naming Kreto Inc. as the taxpayer's information designee. Fills the official IRS PDF template with the taxpayer's entity data and selected tax matters / years, uploads the unsigned PDF to Supabase Storage, creates a draft poa_authorizations row and a signature_requests row, returns the signing URL. The taxpayer (authorized signer on the entity) signs via the existing signing flow; finalization writes the signed PDF URL back to the poa_authorizations row.
Request body PoaFilingGenerate8821Inputrequired
| Field | Type | Required | Description |
|---|---|---|---|
employerEntityId | string | required | — |
taxMatters | array<enum: "income" | "employment" | "excise" | "estate" | …> | required | — |
taxYears | array<integer> | required | — |
signerEmail | string · email | optional | — |
signerTitle | string | optional | — |
Responses
- 200Successful invocation
PoaFilingGenerate8821OutputField Type Required Description poaAuthorizationIdstringrequired — signatureRequestIdstringrequired — signingUrlstringrequired — unsignedPdfUrlstringrequired — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/poa-filing.listPendingFilingsAdmin-only: list signed IRS Form 8821 POAs awaiting filing or in post-filing IRS states. Cross-tenant (Kreto staff console). Returns submission_status, signer info, filing_date, and CAF number for each row. Use to triage what 8821s are ready to upload to irs.gov/Submit8821, or to audit recent filings.
Admin-only: list signed IRS Form 8821 POAs awaiting filing or in post-filing IRS states. Cross-tenant (Kreto staff console). Returns submission_status, signer info, filing_date, and CAF number for each row. Use to triage what 8821s are ready to upload to irs.gov/Submit8821, or to audit recent filings.
Request body PoaFilingListPendingFilingsInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
status | enum: "signed" | "submitted" | "accepted" | "rejected" | optional | Filter by submission_status. Omit to receive every non-draft row. |
limit | integer | optional | — |
offset | integer | optional | — |
Responses
- 200Successful invocation
PoaFilingListPendingFilingsOutputField Type Required Description rowsarray<object>required — totalintegerrequired — - 400Validation error (input schema rejected). risk_level=elevated.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/poa-filing.transitionPoaFilingStatusAdmin-only: advance the IRS 8821 filing state machine for a single POA. Allowed: signed→submitted (Kreto staff uploaded to IRS portal), submitted→accepted (record CAF number from IRS ack), submitted→ rejected (record IRS rejection reason). Any other transition errors. Use to mirror IRS portal interactions back into Kreto state.
Admin-only: advance the IRS 8821 filing state machine for a single POA. Allowed: signed→submitted (Kreto staff uploaded to IRS portal), submitted→accepted (record CAF number from IRS ack), submitted→ rejected (record IRS rejection reason). Any other transition errors. Use to mirror IRS portal interactions back into Kreto state.
Request body PoaFilingTransitionPoaFilingStatusInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
poaAuthorizationId | string | required | — |
toStatus | enum: "submitted" | "accepted" | "rejected" | required | — |
cafNumber | string | optional | — |
rejectionReason | string | optional | — |
Responses
- 200Successful invocation
PoaFilingTransitionPoaFilingStatusOutputField Type Required Description poaAuthorizationIdstringrequired — submissionStatusenum: "signed" | "submitted" | "accepted" | "rejected" | …required — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
l2:policy2
POST/v1/policy.getGet the mailbox automation policy for the caller's tenant (or a specific entity): the per-action execution-mode matrix + step-up threshold + outbound posture, and the deadline-escalation ladder. Returns conservative code defaults (isDefault=true) when no policy row exists. AUTONOMOUS — read-only.
Get the mailbox automation policy for the caller's tenant (or a specific entity): the per-action execution-mode matrix + step-up threshold + outbound posture, and the deadline-escalation ladder. Returns conservative code defaults (isDefault=true) when no policy row exists. AUTONOMOUS — read-only.
Request body PolicyGetInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
entityId | string | optional | — |
Responses
- 200Successful invocation
PolicyGetOutputField Type Required Description policyobjectrequired — isDefaultbooleanrequired — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/policy.updateSet the mailbox automation policy for the caller's tenant (or a specific entity): the per-action execution-mode matrix + step-up threshold + outbound posture, and the deadline-escalation ladder. Upserts the single (tenant, entity) row and seals an audit event. NOTIFY — a human-made control-plane change; it never auto-executes anything itself.
Set the mailbox automation policy for the caller's tenant (or a specific entity): the per-action execution-mode matrix + step-up threshold + outbound posture, and the deadline-escalation ladder. Upserts the single (tenant, entity) row and seals an audit event. NOTIFY — a human-made control-plane change; it never auto-executes anything itself.
Request body PolicyUpdateInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
entityId | string | optional | — |
byActionType | object | required | — |
escalation | object | required | — |
Responses
- 200Successful invocation
PolicyUpdateOutputField Type Required Description policyobjectrequired — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
l2:resolutions8
POST/v1/resolutions.getGet a single resolution draft by id for the caller's tenant. Returns the draft letter, status, and the agentic resolution metadata (needs_input/needs_connection/decision_context/trace). Tenant-scoped with a defense-in-depth cross-tenant assertion. AUTONOMOUS — read-only.
Get a single resolution draft by id for the caller's tenant. Returns the draft letter, status, and the agentic resolution metadata (needs_input/needs_connection/decision_context/trace). Tenant-scoped with a defense-in-depth cross-tenant assertion. AUTONOMOUS — read-only.
Request body ResolutionsGetInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
resolutionId | string | required | — |
Responses
- 200Successful invocation
ResolutionsGetOutputField Type Required Description resolutionobjectrequired — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/resolutions.listList all resolution draft versions for a notice (newest version first) for the caller's tenant. Use to surface a notice's proposed responses and their approval status. Tenant-scoped with a defense-in-depth cross-tenant assertion. AUTONOMOUS — read-only.
List all resolution draft versions for a notice (newest version first) for the caller's tenant. Use to surface a notice's proposed responses and their approval status. Tenant-scoped with a defense-in-depth cross-tenant assertion. AUTONOMOUS — read-only.
Request body ResolutionsListInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
noticeId | string | required | — |
Responses
- 200Successful invocation
ResolutionsListOutputField Type Required Description itemsarray<object>required — totalintegerrequired — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/resolutions.reconcileAndDraftReconcile an actionable notice against the entity's connected payroll and draft a resolution. Returns needs_connection (no payroll linked) or needs_input (payroll missing for the period) synchronously; otherwise enqueues the reconcile+draft worker job and returns 'queued' (read the draft + line-level trace via resolutions.get/list). AUTONOMOUS — computes + queues; a human reviews the draft before anything files.
Reconcile an actionable notice against the entity's connected payroll and draft a resolution. Returns needs_connection (no payroll linked) or needs_input (payroll missing for the period) synchronously; otherwise enqueues the reconcile+draft worker job and returns 'queued' (read the draft + line-level trace via resolutions.get/list). AUTONOMOUS — computes + queues; a human reviews the draft before anything files.
Request body ResolutionsReconcileAndDraftInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
noticeId | string | required | — |
Responses
- 200Successful invocation
ResolutionsReconcileAndDraftOutput - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/resolutions.supplyInputSupply the missing fields a draft is blocked on, clearing needs_input (AC-6). Records the values so the reconcile can re-run, and surfaces the draft for review. NOTIFY — writes a human-reviewed update; files nothing.
Supply the missing fields a draft is blocked on, clearing needs_input (AC-6). Records the values so the reconcile can re-run, and surfaces the draft for review. NOTIFY — writes a human-reviewed update; files nothing.
Request body ResolutionsSupplyInputInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
resolutionId | string | required | — |
inputs | object | required | — |
Responses
- 200Successful invocation
ResolutionsSupplyInputOutputField Type Required Description resolutionobjectrequired — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/resolutions.recordOutcomeRecord an agency response on a resolution — acceptance confirms the matter, anything else reopens it (AC-12) — and seal the transition into the SHA-256 audit chain. AUTONOMOUS — deterministic classification of the agency's reply; no human gate.
Record an agency response on a resolution — acceptance confirms the matter, anything else reopens it (AC-12) — and seal the transition into the SHA-256 audit chain. AUTONOMOUS — deterministic classification of the agency's reply; no human gate.
Request body ResolutionsRecordOutcomeInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
resolutionId | string | required | — |
agencyResponseType | enum: "acceptance" | "counter" | "additional_info_request" | "rejection" | required | — |
Responses
- 200Successful invocation
ResolutionsRecordOutcomeOutputField Type Required Description resolutionobjectrequired — outcomeenum: "confirmed" | "reopened"required — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/resolutions.approveApprove a resolution draft (transitions draft -> approved). Requires a typed confirmation phrase ("APPROVE"). APPROVAL_REQUIRED — human gate; files/moves nothing by itself (execute is the external-impact step). UI-only: not exposed via MCP/CLI.
Approve a resolution draft (transitions draft -> approved). Requires a typed confirmation phrase ("APPROVE"). APPROVAL_REQUIRED — human gate; files/moves nothing by itself (execute is the external-impact step). UI-only: not exposed via MCP/CLI.
Request body ResolutionsApproveInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
resolutionId | string | required | — |
confirmationPhrase | string | required | Typed confirmation — must equal "APPROVE" (AC-9 typed-confirm). |
Responses
- 200Successful invocation
ResolutionsApproveOutputField Type Required Description resolutionobjectrequired — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/resolutions.rejectReject a resolution draft (transitions draft -> rejected). Records the reason; redraft=true signals the redraft loop, otherwise the matter is finalized. APPROVAL_REQUIRED — human gate; UI-only, not MCP/CLI-exposed.
Reject a resolution draft (transitions draft -> rejected). Records the reason; redraft=true signals the redraft loop, otherwise the matter is finalized. APPROVAL_REQUIRED — human gate; UI-only, not MCP/CLI-exposed.
Request body ResolutionsRejectInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
resolutionId | string | required | — |
reason | string | optional | — |
redraft | boolean | optional | — |
Responses
- 200Successful invocation
ResolutionsRejectOutputField Type Required Description resolutionobjectrequired — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/resolutions.executeExecute an approved resolution: record the agency filing (operator-attested) and advance the notice to ACTIONED, sealing a hash-chained audit receipt. Requires the draft to be 'approved' (post-approval invariant) and not already executed. APPROVAL_REQUIRED — UI/session-only (not MCP/CLI); Kreto records the filing, it does not auto-transmit.
Execute an approved resolution: record the agency filing (operator-attested) and advance the notice to ACTIONED, sealing a hash-chained audit receipt. Requires the draft to be 'approved' (post-approval invariant) and not already executed. APPROVAL_REQUIRED — UI/session-only (not MCP/CLI); Kreto records the filing, it does not auto-transmit.
Request body ResolutionsExecuteInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
resolutionId | string | required | — |
filingMethod | enum: "mail" | "fax" | "online_portal" | "email" | … | required | — |
note | string | optional | — |
Responses
- 200Successful invocation
ResolutionsExecuteOutputField Type Required Description resolutionobjectrequired — filingobjectrequired — sealedAtstringrequired — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
l2:signature-consents3
POST/v1/signature-consents.captureConsentPersist an employer officer's signature + scoped consent for state filings. Use when an officer has signed on a canvas and explicitly authorized Kreto to apply the captured signature to per-state PDFs (Middesk-match signature-warehouse model). Idempotent: returns existing un-revoked consent for the same (officer, scope) instead of duplicating.
Persist an employer officer's signature + scoped consent for state filings. Use when an officer has signed on a canvas and explicitly authorized Kreto to apply the captured signature to per-state PDFs (Middesk-match signature-warehouse model). Idempotent: returns existing un-revoked consent for the same (officer, scope) instead of duplicating.
Request body SignatureConsentsCaptureConsentInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
entityId | string | required | — |
officerMemberId | string | required | — |
scope | enum: "sos_and_payroll_tax" | "state_registration_only" | "all_state_filings" | required | — |
signatureDataUrl | string | required | — |
ip | string | required | — |
userAgent | string | required | — |
Responses
- 200Successful invocation
SignatureConsentsCaptureConsentOutputField Type Required Description consentobjectrequired — isNewCapturebooleanrequired — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/signature-consents.getActiveConsentLook up the latest active (un-revoked) signature consent for an entity + scope. Use when generating a state filing to find the signature image to stamp on the PDF. Returns null if no active consent exists — caller should prompt the officer to sign first.
Look up the latest active (un-revoked) signature consent for an entity + scope. Use when generating a state filing to find the signature image to stamp on the PDF. Returns null if no active consent exists — caller should prompt the officer to sign first.
Request body SignatureConsentsGetActiveConsentInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
entityId | string | required | — |
scope | enum: "sos_and_payroll_tax" | "state_registration_only" | "all_state_filings" | required | — |
officerMemberId | string | optional | — |
Responses
- 200Successful invocation
SignatureConsentsGetActiveConsentOutputField Type Required Description consentobjectrequired — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/signature-consents.revokeConsentSoft-revoke a signature consent so it cannot be applied to future filings. Past filings already stamped with the signature retain their stamps (audit immutability). Use when an officer leaves the company or the customer wants to withdraw authorization.
Soft-revoke a signature consent so it cannot be applied to future filings. Past filings already stamped with the signature retain their stamps (audit immutability). Use when an officer leaves the company or the customer wants to withdraw authorization.
Request body SignatureConsentsRevokeConsentInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
consentId | string | required | — |
revocationReason | string | required | — |
Responses
- 200Successful invocation
SignatureConsentsRevokeConsentOutputField Type Required Description consentobjectrequired — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
l2:state-coverage1
POST/v1/state-coverage.getByStateFetch one US state's compliance coverage for an employer: all registrations (with state account numbers), open notices (not in terminal status), and open recommendations. Use when an agent or the UI drawer needs deep detail on a single state. Example agent question: 'What's our SUI registration status in California?' Returns empty arrays for any signal that has no data — never throws on missing rows.
Fetch one US state's compliance coverage for an employer: all registrations (with state account numbers), open notices (not in terminal status), and open recommendations. Use when an agent or the UI drawer needs deep detail on a single state. Example agent question: 'What's our SUI registration status in California?' Returns empty arrays for any signal that has no data — never throws on missing rows.
Request body StateCoverageGetByStateInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
tenantId | string | required | — |
employerEntityId | string | required | — |
stateCode | string | required | — |
Responses
- 200Successful invocation
StateCoverageGetByStateOutputField Type Required Description stateCodestringrequired — registrationsarray<object>required — openNoticesarray<object>required — recommendationsarray<object>required — - 400Validation error (input schema rejected). risk_level=elevated.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
l2:state-registration26
POST/v1/state-registration.detectNewStateRequirementGiven a StateChangeEvent (an employee moved from one state to another), return the requirements that apply for the destination state. Reads the TS rules registry; does NOT write to DB. AUTONOMOUS — agents may call freely; the trigger pipeline lives in PR-D's worker handler.
Given a StateChangeEvent (an employee moved from one state to another), return the requirements that apply for the destination state. Reads the TS rules registry; does NOT write to DB. AUTONOMOUS — agents may call freely; the trigger pipeline lives in PR-D's worker handler.
Request body StateRegistrationDetectNewStateRequirementInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
stateChangeEvent | object | required | — |
Responses
- 200Successful invocation
StateRegistrationDetectNewStateRequirementOutputField Type Required Description requirementsarray<object>required — reasoningstringrequired — stateSupportedbooleanrequired — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/state-registration.listRequiredAccountsList required state-agency accounts for a given state. When employerEntityId is supplied, also returns the subset of requirements already registered (status NOT IN rejected/expired) for that employer. Reads from rules registry. AUTONOMOUS.
List required state-agency accounts for a given state. When employerEntityId is supplied, also returns the subset of requirements already registered (status NOT IN rejected/expired) for that employer. Reads from rules registry. AUTONOMOUS.
Request body StateRegistrationListRequiredAccountsInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
stateCode | string | required | — |
employerEntityId | string | optional | — |
Responses
- 200Successful invocation
StateRegistrationListRequiredAccountsOutputField Type Required Description stateCodestringrequired — stateSupportedbooleanrequired — accountsarray<object>required — alreadyRegisteredarray<enum: "sui_registration" | "withholding_registration" | "workers_comp" | "pfml" | …>required — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/state-registration.prepareRegistrationFormValidate a registration form payload against the per-state Zod schema and persist (upsert) a row in employer_state_registrations with status='prepared'. dryRun=true returns the validated payload without persisting. APPROVAL_REQUIRED — Phase 0 metadata only (HITL gate in Phase 3).
Validate a registration form payload against the per-state Zod schema and persist (upsert) a row in employer_state_registrations with status='prepared'. dryRun=true returns the validated payload without persisting. APPROVAL_REQUIRED — Phase 0 metadata only (HITL gate in Phase 3).
Request body StateRegistrationPrepareRegistrationFormInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
entityId | string | required | — |
stateCode | string | required | — |
requirementType | enum: "sui_registration" | "withholding_registration" | "workers_comp" | "pfml" | … | required | — |
formPayload | object | optional | — |
dryRun | boolean | optional | — |
source | enum: "manual" | "mosey" | "portal" | optional | — |
sourceExternalId | string | optional | — |
Responses
- 200Successful invocation
StateRegistrationPrepareRegistrationFormOutputField Type Required Description registrationobjectrequired — validatedPayloadobjectoptional — dryRunbooleanrequired — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/state-registration.submitRegistrationSubmit a prepared registration to the state portal via Browserbase. The most consequential method in Phase E — actually files with a government agency. APPROVAL_REQUIRED (Phase 0 metadata-only; HITL gate in Phase 3). Dispatches via the StatePortalAdapter registry; throws NotImplementedError for states without a wired adapter.
Submit a prepared registration to the state portal via Browserbase. The most consequential method in Phase E — actually files with a government agency. APPROVAL_REQUIRED (Phase 0 metadata-only; HITL gate in Phase 3). Dispatches via the StatePortalAdapter registry; throws NotImplementedError for states without a wired adapter.
Request body StateRegistrationSubmitRegistrationInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
registrationId | string | required | — |
dryRun | boolean | optional | — |
Responses
- 200Successful invocation
StateRegistrationSubmitRegistrationOutputField Type Required Description registrationobjectrequired — dryRunbooleanrequired — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/state-registration.checkRegistrationStatusReturn the current status of a registration. PR-A reads DB last-known state only (pollSource='db_only'). PR-B/C wires actual portal polling via Browserbase (pollSource='portal_polled'). AUTONOMOUS.
Return the current status of a registration. PR-A reads DB last-known state only (pollSource='db_only'). PR-B/C wires actual portal polling via Browserbase (pollSource='portal_polled'). AUTONOMOUS.
Request body StateRegistrationCheckRegistrationStatusInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
registrationId | string | required | — |
Responses
- 200Successful invocation
StateRegistrationCheckRegistrationStatusOutputField Type Required Description registrationobjectrequired — pollSourceenum: "db_only" | "portal_polled"required — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/state-registration.getRegistrationByEntityLook up the in-flight registration for (tenantId, entityId, stateCode, requirementType). Returns null when no row matches (rejected/expired excluded). AUTONOMOUS.
Look up the in-flight registration for (tenantId, entityId, stateCode, requirementType). Returns null when no row matches (rejected/expired excluded). AUTONOMOUS.
Request body StateRegistrationGetRegistrationByEntityInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
entityId | string | required | — |
stateCode | string | required | — |
requirementType | enum: "sui_registration" | "withholding_registration" | "workers_comp" | "pfml" | … | required | — |
Responses
- 200Successful invocation
StateRegistrationGetRegistrationByEntityOutputField Type Required Description registrationobjectrequired — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/state-registration.listRegistrationsPaginated read of employer_state_registrations rows for the tracking UI. Tenant-scoped via ctx.tenantId; optional entity / status / state / requirement_type / source filters. Returns at most pageSize rows per call (default 25, max 100).
Paginated read of employer_state_registrations rows for the tracking UI. Tenant-scoped via ctx.tenantId; optional entity / status / state / requirement_type / source filters. Returns at most pageSize rows per call (default 25, max 100).
Request body StateRegistrationListRegistrationsInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
entityId | string | optional | — |
status | enum: "pending" | "prepared" | "awaiting_approval" | "preflight_failed" | … | optional | — |
stateCode | string | optional | — |
requirementType | enum: "sui_registration" | "withholding_registration" | "workers_comp" | "pfml" | … | optional | — |
source | enum: "manual" | "mosey" | "portal" | optional | — |
page | integer | optional | — |
pageSize | integer | optional | — |
Responses
- 200Successful invocation
StateRegistrationListRegistrationsOutputField Type Required Description registrationsarray<object>required — pageintegerrequired — pageSizeintegerrequired — totalintegerrequired — hasMorebooleanrequired — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/state-registration.transitionStatusApply a manual CPA-driven status transition to an existing registration row. Validates the (from, to) pair against the per-state allowedTransitions matrix (with universal default fallback). Writes a structured audit event capturing the transition + reason. NOTIFY classification: agents can call but the action is logged for human review.
Apply a manual CPA-driven status transition to an existing registration row. Validates the (from, to) pair against the per-state allowedTransitions matrix (with universal default fallback). Writes a structured audit event capturing the transition + reason. NOTIFY classification: agents can call but the action is logged for human review.
Request body StateRegistrationTransitionStatusInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
registrationId | string | required | — |
newStatus | enum: "pending" | "prepared" | "awaiting_approval" | "preflight_failed" | … | required | — |
reason | string | required | — |
stateAccountNumber | string | optional | — |
filedAt | string · date-time | optional | — |
Responses
- 200Successful invocation
StateRegistrationTransitionStatusOutputField Type Required Description registrationobjectrequired — fromStatusenum: "pending" | "prepared" | "awaiting_approval" | "preflight_failed" | …required — toStatusenum: "pending" | "prepared" | "awaiting_approval" | "preflight_failed" | …required — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/state-registration.updateRegistrationMetadataManually edit the tracker metadata fields (assigned_rate as a decimal fraction, assigned_deposit_frequency, effective_date, next_renewal_at) on an existing registration row. Absent key = unchanged, null = clear. Appends a human-readable notes line and a hash-chained audit_events row carrying per-field old → new + the required reason. `source` is never changed (creation provenance). NOTIFY classification: agents can call but the action is logged for human review.
Manually edit the tracker metadata fields (assigned_rate as a decimal fraction, assigned_deposit_frequency, effective_date, next_renewal_at) on an existing registration row. Absent key = unchanged, null = clear. Appends a human-readable notes line and a hash-chained audit_events row carrying per-field old → new + the required reason. `source` is never changed (creation provenance). NOTIFY classification: agents can call but the action is logged for human review.
Request body StateRegistrationUpdateRegistrationMetadataInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
registrationId | string | required | — |
assignedRate | number | optional | — |
assignedDepositFrequency | enum: "weekly" | "biweekly" | "semimonthly" | "monthly" | … | optional | — |
effectiveDate | string | optional | — |
nextRenewalAt | string | optional | — |
reason | string | required | — |
Responses
- 200Successful invocation
StateRegistrationUpdateRegistrationMetadataOutputField Type Required Description registrationobjectrequired — changedFieldsarray<string>required — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/state-registration.recordPortalResultInbound write path for state portal scrapers. Transitions a registration row to approved or rejected based on the portal's outcome, sets state_account_number on success, captures last_error on failure, and emits a recommendation row that the alert cron uses to email/push the CPA team. APPROVAL_REQUIRED per /goal Q8 decision — customer + external-facing writes are NOT MCP-exposable; the audit row carries the elevated risk level so Phase 3 HITL gates these calls. Auth: server-to-server via API key with scope state_registration.write.
Inbound write path for state portal scrapers. Transitions a registration row to approved or rejected based on the portal's outcome, sets state_account_number on success, captures last_error on failure, and emits a recommendation row that the alert cron uses to email/push the CPA team. APPROVAL_REQUIRED per /goal Q8 decision — customer + external-facing writes are NOT MCP-exposable; the audit row carries the elevated risk level so Phase 3 HITL gates these calls. Auth: server-to-server via API key with scope state_registration.write.
Request body StateRegistrationRecordPortalResultInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
registrationId | string | required | — |
outcome | enum: "approved" | "rejected" | required | — |
stateAccountNumber | string | optional | — |
decidedAt | string · date-time | optional | — |
lastError | string | optional | — |
Responses
- 200Successful invocation
StateRegistrationRecordPortalResultOutputField Type Required Description registrationobjectrequired — recommendationIdstringrequired — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/state-registration.generateDe1FilingGenerate a draft California Form DE 1 (covers SUI + Withholding + SDI/PFL on a single CA EDD form) filled with the employer's intake data and stamped with the captured officer signature. Creates a state_filings parent row + 3 employer_state_registrations rows (SUI/Withholding/PFML) all linked via filing_id. NOTIFY risk: this is a draft for human review before CP-CA3 submits to myEDD.
Generate a draft California Form DE 1 (covers SUI + Withholding + SDI/PFL on a single CA EDD form) filled with the employer's intake data and stamped with the captured officer signature. Creates a state_filings parent row + 3 employer_state_registrations rows (SUI/Withholding/PFML) all linked via filing_id. NOTIFY risk: this is a draft for human review before CP-CA3 submits to myEDD.
Request body StateRegistrationGenerateDe1FilingInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
employerEntityId | string | required | — |
recommendationId | string | optional | — |
signatureConsentId | string | required | — |
intake | object | required | — |
Responses
- 200Successful invocation
StateRegistrationGenerateDe1FilingOutputField Type Required Description filingIdstringrequired — filingPdfUrlstringrequired — employerStateRegistrationIdsarray<string>required — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/state-registration.generateStateFilingState-agnostic filing generator. Resolves the per-state rule for the given stateCode, validates intake against rule.stateIntakeSchema, embeds the captured signature, generates a draft PDF (from rule.pdfTemplatePath if set, else programmatic), and creates a state_filings parent row + one employer_state_registrations row per covered requirement_type. NOTIFY risk: draft only — submission to the state portal is CP-CA3 (APPROVAL_REQUIRED). Replaces the CA-specific generateDe1Filing for all new states.
State-agnostic filing generator. Resolves the per-state rule for the given stateCode, validates intake against rule.stateIntakeSchema, embeds the captured signature, generates a draft PDF (from rule.pdfTemplatePath if set, else programmatic), and creates a state_filings parent row + one employer_state_registrations row per covered requirement_type. NOTIFY risk: draft only — submission to the state portal is CP-CA3 (APPROVAL_REQUIRED). Replaces the CA-specific generateDe1Filing for all new states.
Request body StateRegistrationGenerateStateFilingInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
stateCode | string | required | — |
employerEntityId | string | required | — |
recommendationId | string | optional | — |
signatureConsentId | string | required | — |
intake | object | required | — |
Responses
- 200Successful invocation
StateRegistrationGenerateStateFilingOutputField Type Required Description filingIdstringrequired — filingPdfUrlstringrequired — employerStateRegistrationIdsarray<string>required — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/state-registration.saveIntakeDraftUpsert the in-progress State Registration Wizard intake for a given (employer, state) so wizard state survives a refresh / crash / cross-device resume. Draft-only (NOTIFY): captures answers + resume metadata, generates no filing and submits nothing. One row per (tenant, employer, state) via the table's UNIQUE constraint — re-saving updates, never duplicates.
Upsert the in-progress State Registration Wizard intake for a given (employer, state) so wizard state survives a refresh / crash / cross-device resume. Draft-only (NOTIFY): captures answers + resume metadata, generates no filing and submits nothing. One row per (tenant, employer, state) via the table's UNIQUE constraint — re-saving updates, never duplicates.
Request body StateRegistrationSaveIntakeDraftInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
employerEntityId | string | required | — |
recommendationId | string | optional | — |
stateCode | string | required | — |
reasonForRegistering | string | optional | — |
qualifiers | object | optional | — |
stateSpecificData | object | required | — |
Responses
- 200Successful invocation
StateRegistrationSaveIntakeDraftOutputField Type Required Description draftIdstringrequired — updatedAtstringrequired — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/state-registration.provisionPortalAccountAllocate a Kreto-owned portal-account credential for a (tenant, entity, state, agency) tuple. Generates a unique alias e-mail of the form <slug>.portal-<state>-<agency>@kreto.ai, generates a strong base64url password, and writes the credential to vault under agency_id='portal_<stateCode>'. Idempotent: re-call with the same tuple returns the existing credential. APPROVAL_REQUIRED (Phase 0 metadata-only; KRT-1554 step-up gates later).
Allocate a Kreto-owned portal-account credential for a (tenant, entity, state, agency) tuple. Generates a unique alias e-mail of the form <slug>.portal-<state>-<agency>@kreto.ai, generates a strong base64url password, and writes the credential to vault under agency_id='portal_<stateCode>'. Idempotent: re-call with the same tuple returns the existing credential. APPROVAL_REQUIRED (Phase 0 metadata-only; KRT-1554 step-up gates later).
Request body StateRegistrationProvisionPortalAccountInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
entityId | string · uuid | required | — |
stateCode | string | required | — |
agencyCode | string | required | — |
Responses
- 200Successful invocation
StateRegistrationProvisionPortalAccountOutputField Type Required Description credentialIdstring · uuidrequired — aliasEmailstring · emailrequired — agencyIdstringrequired — statusstringrequired — passwordstringrequired — newlyProvisionedbooleanrequired — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/state-registration.listCatalogRulesBrowse the state-registration catalog (state_filing_rules, global config — NO tenant filter). Optional filters: stateCode, requirementType, verificationStatus, needsResearch, monopolistic, jurisdictionType. Returns the matching rows plus HONEST per-status counts ({unverified, human_reviewed, verified}) for the filtered set — never a 'done/complete' claim (AC-23). AUTONOMOUS, read-only.
Browse the state-registration catalog (state_filing_rules, global config — NO tenant filter). Optional filters: stateCode, requirementType, verificationStatus, needsResearch, monopolistic, jurisdictionType. Returns the matching rows plus HONEST per-status counts ({unverified, human_reviewed, verified}) for the filtered set — never a 'done/complete' claim (AC-23). AUTONOMOUS, read-only.
Request body StateRegistrationListCatalogRulesInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
stateCode | string | optional | — |
requirementType | enum: "sui_registration" | "withholding_registration" | "workers_comp" | "pfml" | … | optional | — |
verificationStatus | enum: "unverified" | "human_reviewed" | "verified" | optional | — |
needsResearch | boolean | optional | — |
monopolistic | boolean | optional | — |
jurisdictionType | enum: "federal" | "state" | "locality" | optional | — |
Responses
- 200Successful invocation
StateRegistrationListCatalogRulesOutputField Type Required Description rowsarray<object>required — countsobjectrequired — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/state-registration.promoteCatalogRuleHuman gate: promote a catalog cell along the verification ladder (unverified → human_reviewed → verified). APPROVAL_REQUIRED, UI-only — excluded from MCP/CLI, and the handler REJECTS any non-human principal before any write (AC-20). Verifying requires provenance (source_url + retrieved_at, AC-18). Stamps reviewed_by / last_reviewed_at, and on verify also verified_at / verified_by / needs_research=false.
Human gate: promote a catalog cell along the verification ladder (unverified → human_reviewed → verified). APPROVAL_REQUIRED, UI-only — excluded from MCP/CLI, and the handler REJECTS any non-human principal before any write (AC-20). Verifying requires provenance (source_url + retrieved_at, AC-18). Stamps reviewed_by / last_reviewed_at, and on verify also verified_at / verified_by / needs_research=false.
Request body StateRegistrationPromoteCatalogRuleInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
stateCode | string | required | — |
requirementType | enum: "sui_registration" | "withholding_registration" | "workers_comp" | "pfml" | … | required | — |
toStatus | enum: "human_reviewed" | "verified" | required | — |
reason | string | optional | — |
Responses
- 200Successful invocation
StateRegistrationPromoteCatalogRuleOutputField Type Required Description stateCodestringrequired — requirementTypeenum: "sui_registration" | "withholding_registration" | "workers_comp" | "pfml" | …required — fromStatusenum: "unverified" | "human_reviewed" | "verified"required — toStatusenum: "unverified" | "human_reviewed" | "verified"required — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/state-registration.getCatalogRuleRead one catalog cell (state_filing_rules, global config — NO tenant filter): the rule row plus its typed ordered steps (state_filing_rule_steps), its prerequisite edges (state_filing_rule_prerequisites), and the resolved jurisdiction (via jurisdiction_code, else null). Powers the Cell Detail screen (jobs a+b, AC-5). AUTONOMOUS, read-only.
Read one catalog cell (state_filing_rules, global config — NO tenant filter): the rule row plus its typed ordered steps (state_filing_rule_steps), its prerequisite edges (state_filing_rule_prerequisites), and the resolved jurisdiction (via jurisdiction_code, else null). Powers the Cell Detail screen (jobs a+b, AC-5). AUTONOMOUS, read-only.
Request body StateRegistrationGetCatalogRuleInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
stateCode | string | required | — |
requirementType | enum: "sui_registration" | "withholding_registration" | "workers_comp" | "pfml" | … | required | — |
Responses
- 200Successful invocation
StateRegistrationGetCatalogRuleOutputField Type Required Description ruleobjectrequired — stepsarray<object>required — prerequisitesarray<object>required — jurisdictionobjectrequired — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/state-registration.listFilingRuleStepsList the typed, ordered registration steps for a (state, requirement) cell (state_filing_rule_steps, global config — NO tenant filter), ordered by step_order. The canonical step sequence is typed rows, never a prose blob (AC-7). AUTONOMOUS, read-only.
List the typed, ordered registration steps for a (state, requirement) cell (state_filing_rule_steps, global config — NO tenant filter), ordered by step_order. The canonical step sequence is typed rows, never a prose blob (AC-7). AUTONOMOUS, read-only.
Request body StateRegistrationListFilingRuleStepsInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
stateCode | string | required | — |
requirementType | enum: "sui_registration" | "withholding_registration" | "workers_comp" | "pfml" | … | required | — |
Responses
- 200Successful invocation
StateRegistrationListFilingRuleStepsOutputField Type Required Description stepsarray<object>required — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/state-registration.listFilingRulePrerequisitesList the prerequisite dependency edges for a (state, requirement) cell (state_filing_rule_prerequisites, global config — NO tenant filter). Edges model account-type dependencies and SOS foreign qualification (prerequisite_kind='sos_foreign_qual', an edge — NOT a 6th requirement_type), queryable as a dependency chain (AC-10/13). AUTONOMOUS, read-only.
List the prerequisite dependency edges for a (state, requirement) cell (state_filing_rule_prerequisites, global config — NO tenant filter). Edges model account-type dependencies and SOS foreign qualification (prerequisite_kind='sos_foreign_qual', an edge — NOT a 6th requirement_type), queryable as a dependency chain (AC-10/13). AUTONOMOUS, read-only.
Request body StateRegistrationListFilingRulePrerequisitesInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
stateCode | string | required | — |
requirementType | enum: "sui_registration" | "withholding_registration" | "workers_comp" | "pfml" | … | required | — |
Responses
- 200Successful invocation
StateRegistrationListFilingRulePrerequisitesOutputField Type Required Description prerequisitesarray<object>required — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/state-registration.listJurisdictionsList jurisdictions (federal | state | locality) from the jurisdictions table (global config — NO tenant filter). Optional filters: jurisdictionType, parentCode. Locality-ready model — v1 seeds state-grain only, but a locality is just a future row (AC-15/16). AUTONOMOUS, read-only.
List jurisdictions (federal | state | locality) from the jurisdictions table (global config — NO tenant filter). Optional filters: jurisdictionType, parentCode. Locality-ready model — v1 seeds state-grain only, but a locality is just a future row (AC-15/16). AUTONOMOUS, read-only.
Request body StateRegistrationListJurisdictionsInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
jurisdictionType | enum: "federal" | "state" | "locality" | optional | — |
parentCode | string | optional | — |
Responses
- 200Successful invocation
StateRegistrationListJurisdictionsOutputField Type Required Description jurisdictionsarray<object>required — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/state-registration.proposeFilingRuleResearch one (state, requirement) catalog cell via the Claude + web_search agent and upsert an UNVERIFIED proposal onto the cell BY PK (state_filing_rules, global config — NO tenant filter). The write ALWAYS leaves verification_status='unverified' and NEVER sets verified/human_reviewed (AC-19/20 — agents may never verify); writes provenance (source_url + retrieved_at, AC-18); idempotent-by-PK (AC-22). MUST NOT downgrade a human-promoted cell: on a human_reviewed OR verified cell it leaves the authoritative fields untouched and returns the existing row + the fresh proposal so a human can compare (no-downgrade). PII-free. NOTIFY: agents may call; a human reviews the proposal before promotion.
Research one (state, requirement) catalog cell via the Claude + web_search agent and upsert an UNVERIFIED proposal onto the cell BY PK (state_filing_rules, global config — NO tenant filter). The write ALWAYS leaves verification_status='unverified' and NEVER sets verified/human_reviewed (AC-19/20 — agents may never verify); writes provenance (source_url + retrieved_at, AC-18); idempotent-by-PK (AC-22). MUST NOT downgrade a human-promoted cell: on a human_reviewed OR verified cell it leaves the authoritative fields untouched and returns the existing row + the fresh proposal so a human can compare (no-downgrade). PII-free. NOTIFY: agents may call; a human reviews the proposal before promotion.
Request body StateRegistrationProposeFilingRuleInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
stateCode | string | required | — |
requirementType | enum: "sui_registration" | "withholding_registration" | "workers_comp" | "pfml" | … | required | — |
Responses
- 200Successful invocation
StateRegistrationProposeFilingRuleOutputField Type Required Description rowobjectrequired — proposalobjectrequired — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/state-registration.approveRegistrationFilingRecord a CPA's approval to file a prepared registration and, for fee-bearing filings, authorize payment up to a bound amount (AC-15). The consequential human gate — APPROVAL_REQUIRED, UI-only, never exposed to MCP/CLI. Moves the registration to 'awaiting_approval' and enqueues pre-flight. Handler: Phase B.
Record a CPA's approval to file a prepared registration and, for fee-bearing filings, authorize payment up to a bound amount (AC-15). The consequential human gate — APPROVAL_REQUIRED, UI-only, never exposed to MCP/CLI. Moves the registration to 'awaiting_approval' and enqueues pre-flight. Handler: Phase B.
Request body StateRegistrationApproveRegistrationFilingInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
registrationId | string · uuid | required | — |
authorizedAmountCents | integer | required | — |
billingDisclosure | string | optional | — |
Responses
- 200Successful invocation
StateRegistrationApproveRegistrationFilingOutputField Type Required Description registrationIdstring · uuidrequired — statusstringrequired — approvalIdstring · uuidrequired — preflightobjectrequired — enqueuedbooleanrequired — feeobjectrequired — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/state-registration.runFilingPreflightRun the pre-flight filing validator (KRT-1544 rules: registration status, duplicate-account, idempotency, payload completeness) before any browser session launches (AC-2). Read-only, AUTONOMOUS. A failure blocks the filing and names the failing rule. Handler: Phase B.
Run the pre-flight filing validator (KRT-1544 rules: registration status, duplicate-account, idempotency, payload completeness) before any browser session launches (AC-2). Read-only, AUTONOMOUS. A failure blocks the filing and names the failing rule. Handler: Phase B.
Request body StateRegistrationRunFilingPreflightInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
registrationId | string · uuid | required | — |
Responses
- 200Successful invocation
StateRegistrationRunFilingPreflightOutputField Type Required Description okbooleanrequired — failuresarray<object>required — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/state-registration.verifyFilingOutcomeVerify an executor's claimed filing outcome against captured evidence (confirmation number + screenshot, optional re-check) before the registration is allowed to flip to 'submitted' (AC-5/AC-6). An unverifiable claim yields 'rejected' → needs_human, never 'submitted'. NOTIFY. Handler: Phase E.
Verify an executor's claimed filing outcome against captured evidence (confirmation number + screenshot, optional re-check) before the registration is allowed to flip to 'submitted' (AC-5/AC-6). An unverifiable claim yields 'rejected' → needs_human, never 'submitted'. NOTIFY. Handler: Phase E.
Request body StateRegistrationVerifyFilingOutcomeInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
attemptId | string · uuid | required | — |
Responses
- 200Successful invocation
StateRegistrationVerifyFilingOutcomeOutputField Type Required Description verdictenum: "confirmed" | "rejected"required — confirmationNumberstringrequired — reasonstringrequired — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/state-registration.storeIssuedCredentialStore a portal credential created during registration into the per-tenant credential vault (AC-11). APPROVAL_REQUIRED — creating a credential is a consequential vault write, so it stays UI-only and is NOT exposed to MCP/CLI (verifier-gate finding: a NOTIFY op would be auto-exposed, contra the approved roster). The secret is captured by the vault layer, never passed in model context. Handler: Phase F (needs a real portal-issued credential).
Store a portal credential created during registration into the per-tenant credential vault (AC-11). APPROVAL_REQUIRED — creating a credential is a consequential vault write, so it stays UI-only and is NOT exposed to MCP/CLI (verifier-gate finding: a NOTIFY op would be auto-exposed, contra the approved roster). The secret is captured by the vault layer, never passed in model context. Handler: Phase F (needs a real portal-issued credential).
Request body StateRegistrationStoreIssuedCredentialInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
registrationId | string · uuid | required | — |
portalUsername | string | required | — |
agencyId | string | required | — |
Responses
- 200Successful invocation
StateRegistrationStoreIssuedCredentialOutputField Type Required Description credentialIdstring · uuidrequired — storedbooleanrequired — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/state-registration.recordManualFilingOutcomeRecord the outcome of a Kreto operator completing a filing from the ops-fallback queue (AC-10). Writes the SAME evidence shape as the agentic path (actor=user, via='manual'). APPROVAL_REQUIRED — a human is doing the consequential act; UI-only, never MCP/CLI. Handler: Phase E.
Record the outcome of a Kreto operator completing a filing from the ops-fallback queue (AC-10). Writes the SAME evidence shape as the agentic path (actor=user, via='manual'). APPROVAL_REQUIRED — a human is doing the consequential act; UI-only, never MCP/CLI. Handler: Phase E.
Request body StateRegistrationRecordManualFilingOutcomeInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
registrationId | string · uuid | required | — |
attemptId | string · uuid | optional | — |
outcome | enum: "submitted" | "rejected" | "needs_more_info" | required | — |
confirmationNumber | string | optional | — |
feeAmountCents | integer | optional | — |
notes | string | optional | — |
Responses
- 200Successful invocation
StateRegistrationRecordManualFilingOutcomeOutputField Type Required Description registrationIdstring · uuidrequired — statusstringrequired — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
l2:team-invitations5
POST/v1/team-invitations.createInvitationCreate a team-invitation row, generate single-use accept token, and send the invite email. Returns plaintext accept_url ONCE.
Create a team-invitation row, generate single-use accept token, and send the invite email. Returns plaintext accept_url ONCE.
Request body TeamInvitationsCreateInvitationInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
entity_id | string · uuid | optional | — |
email | string · email | required | — |
role | enum: "controller" | "viewer" | required | — |
Responses
- 200Successful invocation
TeamInvitationsCreateInvitationOutputField Type Required Description invitationobjectrequired — accept_urlstring · urirequired — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/team-invitations.listInvitationsList team invitations for an entity (defaults to caller's owned entity). Never returns plaintext tokens or token hashes.
List team invitations for an entity (defaults to caller's owned entity). Never returns plaintext tokens or token hashes.
Request body TeamInvitationsListInvitationsInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
entity_id | string · uuid | optional | — |
status | enum: "pending" | "accepted" | "revoked" | "expired" | optional | — |
Responses
- 200Successful invocation
TeamInvitationsListInvitationsOutputField Type Required Description invitationsarray<object>required — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/team-invitations.revokeInvitationRevoke a pending invitation. Idempotent for already-revoked/accepted rows (returns current status). Only entity owners may revoke.
Revoke a pending invitation. Idempotent for already-revoked/accepted rows (returns current status). Only entity owners may revoke.
Request body TeamInvitationsRevokeInvitationInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
invitation_id | string · uuid | required | — |
Responses
- 200Successful invocation
TeamInvitationsRevokeInvitationOutputField Type Required Description idstring · uuidrequired — statusstringrequired — - 400Validation error (input schema rejected). risk_level=notify.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/team-invitations.acceptInvitationAccept a team invitation. Verifies token, expiry, self-acceptance, and email-mismatch guards. Inserts entity_members row on success. The caller MUST be signed in as the invited email.
Accept a team invitation. Verifies token, expiry, self-acceptance, and email-mismatch guards. Inserts entity_members row on success. The caller MUST be signed in as the invited email.
Request body TeamInvitationsAcceptInvitationInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
token | string | required | — |
Responses
- 200Successful invocation
TeamInvitationsAcceptInvitationOutputField Type Required Description invitation_idstring · uuidrequired — entity_idstring · uuidrequired — rolestringrequired — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/team-invitations.getInvitationByTokenPublic lookup by plaintext token (hashes on read; never returns hash or plaintext). Used by /accept-team-invite/[token] for render.
Public lookup by plaintext token (hashes on read; never returns hash or plaintext). Used by /accept-team-invite/[token] for render.
Request body TeamInvitationsGetInvitationByTokenInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
token | string | required | — |
Responses
- 200Successful invocation
TeamInvitationsGetInvitationByTokenOutputField Type Required Description invitationobjectrequired — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
l2:vault4
POST/v1/vault.getPolicyRead the account's vault policy (who may reveal plaintext, per-portal MFA overrides, notification routing), the immutable hard floors, and the break-glass lock state. Use to check whether vault operations are currently halted for the tenant.
Read the account's vault policy (who may reveal plaintext, per-portal MFA overrides, notification routing), the immutable hard floors, and the break-glass lock state. Use to check whether vault operations are currently halted for the tenant.
Request body VaultGetPolicyInputrequired
application/json
Responses
- 200Successful invocation
VaultGetPolicyOutputField Type Required Description policyobjectrequired — lockobjectrequired — vaultV1Enforcementbooleanrequired — - 400Validation error (input schema rejected). risk_level=autonomous.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/vault.setPolicyUpdate the account's configurable vault policy: reveal visibility, per-portal MFA strategy overrides, notification routing. The hard floors (money approval, freeze-on-first-failure) are not accepted by this method by construction.
Update the account's configurable vault policy: reveal visibility, per-portal MFA strategy overrides, notification routing. The hard floors (money approval, freeze-on-first-failure) are not accepted by this method by construction.
Request body VaultSetPolicyInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
revealVisibility | enum: "members" | "admins_only" | optional | — |
mfaMatrixOverride | object | optional | — |
notificationRouting | object | optional | — |
Responses
- 200Successful invocation
VaultSetPolicyOutputField Type Required Description policyobjectrequired — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/vault.breakGlassEmergency brake: immediately halt all credential decryption, use, rotation, and reveal for the tenant WITHOUT destroying key material. Reversible — restoring requires dual confirmation. Use on suspected compromise.
Emergency brake: immediately halt all credential decryption, use, rotation, and reveal for the tenant WITHOUT destroying key material. Reversible — restoring requires dual confirmation. Use on suspected compromise.
Request body VaultBreakGlassInputrequired
| Field | Type | Required | Description |
|---|---|---|---|
reason | string | optional | — |
Responses
- 200Successful invocation
VaultBreakGlassOutputField Type Required Description lockedenum: truerequired — lockedAtstringrequired — alreadyLockedbooleanrequired — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
POST/v1/vault.restoreSecond half of break-glass: lift the tenant-wide vault halt. Requires two confirmations from DIFFERENT humans (interim out-of-band dual-confirm until KRT-1554 step-up auth ships). The first call marks the restore pending; a second call by a different user completes it.
Second half of break-glass: lift the tenant-wide vault halt. Requires two confirmations from DIFFERENT humans (interim out-of-band dual-confirm until KRT-1554 step-up auth ships). The first call marks the restore pending; a second call by a different user completes it.
Request body VaultRestoreInputrequired
application/json
Responses
- 200Successful invocation
VaultRestoreOutputField Type Required Description lockedbooleanrequired — restorePendingbooleanrequired — restoredbooleanrequired — secondConfirmerRequiredbooleanrequired — - 400Validation error (input schema rejected). risk_level=approval_required.
L2ErrorEnvelope - 401Unauthorized (missing or invalid bearer token)
L2ErrorEnvelope - 403Forbidden (missing scope or RLS denied). APPROVAL_REQUIRED ops additionally need a human approval token; see KRT-1554 step-up flow.
L2ErrorEnvelope - 500Internal server error
L2ErrorEnvelope
My Compliance6
GET/api/my-compliance/profileRead the caller's business profile (employer-tier)
Returns the entity row scoped to the authenticated user via entity_members. Works for both cpa_member (returns first entity) and client_user (returns their single entity). Bearer auth requires employers.read scope.
Responses
- 200Business profile
MyComplianceProfileField Type Required Description entity_idstring · uuidrequired — legal_namestringrequired — ein_last4stringrequired — primary_statestringrequired — compliance_scoreintegerrequired — created_atstring · date-timerequired — - 401Unauthorized
MyComplianceError - 404No business profile linked to this user
MyComplianceError
PATCH/api/my-compliance/profileUpdate business profile fields
Partial update of the caller's entity. Sends only the fields that changed. EIN is stored as last-4 only (PII rule). Bearer auth requires employers.write scope (CPA-tier only today; employer-tier write coming with granular scope expansion).
Request body MyComplianceProfilePatchrequired
| Field | Type | Required | Description |
|---|---|---|---|
legal_name | string | optional | — |
ein_last4 | string | optional | — |
primary_state | string | optional | — |
Responses
- 200Profile updated
MyComplianceProfilePatchResponseField Type Required Description okbooleanrequired — entityobjectrequired — - 400Validation error
MyComplianceError - 404No business profile linked to this user
MyComplianceError
GET/api/my-compliance/auditAudit log for the caller's entity
Read-only timeline of audit_events filtered to the entity the caller belongs to. Composite cursor pagination — pass next_cursor back as `before` to fetch the next page. Bearer auth requires audit.read scope.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
limit | query | integer | optional | — |
before | query | string | optional | Composite cursor in the form '<iso8601>|<uuid>'. Legacy ISO-only cursors also accepted for backwards compatibility. |
Responses
- 200Audit log page
MyComplianceAuditListField Type Required Description eventsarray<MyComplianceAuditEvent>required — next_cursorstringrequired — entity_idstring · uuidoptional — - 400Invalid cursor
MyComplianceError
GET/api/my-compliance/api-tokensList the caller's non-revoked Bearer tokens
Returns API keys created by the authenticated user, filtered to their tenant. Plaintext is NEVER included — only key_prefix + metadata. Bearer auth NOT supported on this route (cookie-session only) to prevent a token from listing or mass-revoking peers.
Responses
- 200Token list (non-revoked only)
MyComplianceApiTokenListField Type Required Description tokensarray<MyComplianceApiToken>required — - 401Unauthorized
MyComplianceError
POST/api/my-compliance/api-tokensMint a new employer-scoped Bearer token
Creates a new api_keys row via the same hash-on-write pipeline as /api/api-keys, but with the scopes constrained to the employer allow-list (notices.read, employers.read, payroll.read, audit.read). Plaintext is returned ONCE in `plaintext` — store it now; we keep only the bcrypt hash. RLS migration 20260615000000 enforces the scope subset at the DB layer too (defense in depth).
Request body MyComplianceApiTokenCreate
| Field | Type | Required | Description |
|---|---|---|---|
name | string | optional | — |
scopes | array<string> | optional | — |
Responses
- 200Token created. Plaintext returned ONCE.
MyComplianceApiTokenCreatedField Type Required Description okbooleanrequired — plaintextstringrequired — tokenobjectrequired — - 500Failed to create token
MyComplianceError
DELETE/api/my-compliance/api-tokensRevoke one of your own Bearer tokens
Soft-delete via revoked_at timestamp; audit traces survive. Scoped to the caller's own tokens by created_by_user_id — you cannot revoke peers' tokens even within the same tenant.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | query | string · uuid | required | UUID of the api_keys row to revoke |
Responses
- 200Token revoked (idempotent — re-revoking is a no-op 200)
MyComplianceOkResponseField Type Required Description okbooleanrequired — - 400Missing token id
MyComplianceError
Notices45
GET/api/notices/{id}/auditGet notice audit trail
Returns the immutable audit chain for a single notice, including every event's hash links and a `chain_valid` boolean attesting that the SHA-256 chain verifies cryptographically.
audit.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Notice UUID |
Responses
- 200Audit chain + integrity attestation
NoticeAuditResponseField Type Required Description okenum: truerequired — notice_idstring · uuidrequired — entriesarray<AuditEntry>required — chain_validbooleanrequired — chain_break_atintegerrequired — totalintegerrequired — - 400Validation error
NoticeValidationErrorResponse - 401Unauthorized
NoticeUnauthorizedResponse - 403Forbidden — missing required scope
NoticeUnauthorizedResponse - 404Notice not found in caller's tenant
NoticeNotFoundResponse - 429Rate limit exceeded
NoticeRateLimitResponse
GET/api/notices/{id}/document-urlGet signed URL for notice document
Returns a 1-hour signed URL for the original notice document. Tenant-scoped: only notices in the caller's tenant resolve to a URL.
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Notice UUID |
Responses
- 200Signed URL (or null if no document is attached)
NoticeDocumentUrlResponseField Type Required Description urlstringrequired — - 400Validation error
NoticeValidationErrorResponse - 401Unauthorized
NoticeUnauthorizedResponse - 403Forbidden — missing required scope
NoticeUnauthorizedResponse - 429Rate limit exceeded
NoticeRateLimitResponse
GET/api/notices/{id}/draft-dataGet latest notice draft
Returns the latest resolution draft for a notice — content, summary, structured action_items, response_type, and status. Falls back to the legacy `response_drafts` table when no `resolution_drafts` row exists.
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Notice UUID |
Responses
- 200Latest draft (or null fields if none exists)
NoticeDraftDataResponseField Type Required Description contentstringrequired — summarystringrequired — action_itemsarray<string>required — response_typestringrequired — statusstringoptional — created_atstring · date-timeoptional — - 400Validation error
NoticeValidationErrorResponse - 401Unauthorized
NoticeUnauthorizedResponse - 403Forbidden — missing required scope
NoticeUnauthorizedResponse - 404Notice not found in caller's tenant
NoticeNotFoundResponse - 429Rate limit exceeded
NoticeRateLimitResponse
PATCH/api/notices/{id}/entityReassign notice to another entity
Re-attribute a notice to a different entity. Both notice and target entity must be in the caller's tenant; the entity is verified before the update so cross-tenant re-attribution is impossible.
notices.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Notice UUID |
Request body NoticeEntityPatchBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
entity_id | string · uuid | required | — |
Responses
- 200Updated
NoticeEntityPatchResponseField Type Required Description successenum: truerequired — - 400Validation error
NoticeValidationErrorResponse - 401Unauthorized
NoticeUnauthorizedResponse - 403Forbidden — missing required scope
NoticeUnauthorizedResponse - 404Notice or target entity not found in caller's tenant
NoticeNotFoundResponse - 429Rate limit exceeded
NoticeRateLimitResponse
POST/api/notices/{id}/confirm-stateConfirm notice state
Confirm or override the state on a notice. Used when AI extraction misses or misclassifies the state and a human corrects it. The override is logged to audit_events for compliance traceability.
notices.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Notice UUID |
Request body NoticeConfirmStateBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
confirmedState | string | required | — |
Responses
- 200Confirmed
NoticeSuccessResponseField Type Required Description successenum: truerequired — - 400Validation error
NoticeValidationErrorResponse - 401Unauthorized
NoticeUnauthorizedResponse - 403Forbidden — missing required scope
NoticeUnauthorizedResponse - 404Notice not found in caller's tenant
NoticeNotFoundResponse - 429Rate limit exceeded
NoticeRateLimitResponse
GET/api/notices/{id}/documentDownload notice document
Streams the original notice document (PDF/PNG/JPEG/TIFF) inline. Browser sees a Kreto URL, not a Supabase storage URL.
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Notice UUID |
Responses
- 200Binary document content (PDF/PNG/JPEG/TIFF) streamed inline. OpenAPI generator requires schemas for each content type — using z.string() (binary) as a generic placeholder; clients should consume the response stream directly per Content-Type header.
string - 400Validation error
NoticeValidationErrorResponse - 401Unauthorized
- 403Forbidden — missing required scope
- 404Document not found / notice not in caller's tenant
- 429Rate limit exceeded
GET/api/notices/{id}/supplementalGet notice supplemental data
Returns the active work_item, document_requests, and messages associated with a notice. All queries tenant-scoped.
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Notice UUID |
Responses
- 200Supplemental bundle
NoticeSupplementalResponseField Type Required Description work_itemNoticeWorkItemrequired — document_requestsarray<NoticeDocumentRequest>required — messagesarray<NoticeMessage>required — sender_namesobjectrequired — - 400Validation error
NoticeValidationErrorResponse - 401Unauthorized
NoticeUnauthorizedResponse - 403Forbidden — missing required scope
NoticeUnauthorizedResponse - 404Notice not found in caller's tenant
NoticeNotFoundResponse - 429Rate limit exceeded
NoticeRateLimitResponse
GET/api/notices/{id}/statusGet notice pipeline status
Returns pipeline status + classification result for a notice (notice_type_classified, classification_confidence, protest_deadline, financial_impact, protest_recommended, assigned_rate, pipeline_status).
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Notice UUID |
Responses
- 200Pipeline status
NoticeStatusResponseField Type Required Description idstring · uuidrequired — notice_typestringrequired — statestringrequired — pipeline_statusstringrequired — notice_type_classifiedstringrequired — classification_confidencenumberrequired — protest_deadlinestring · daterequired — financial_impactnumberrequired — protest_recommendedbooleanrequired — assigned_ratenumberrequired — - 400Validation error
NoticeValidationErrorResponse - 401Unauthorized
NoticeUnauthorizedResponse - 403Forbidden — missing required scope
NoticeUnauthorizedResponse - 404Notice not found in caller's tenant
NoticeNotFoundResponse - 429Rate limit exceeded
NoticeRateLimitResponse
POST/api/notices/{id}/statusUpdate notice triage fields
Update notice triage fields (assigned_rate, is_new_employer). is_new_employer is stored inside extracted_json (no dedicated column).
notices.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Notice UUID |
Request body NoticeStatusPostBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
assigned_rate | number | optional | — |
is_new_employer | boolean | optional | — |
Responses
- 200Updated
NoticeStatusPostResponseField Type Required Description okenum: truerequired — updatedobjectrequired — - 400Validation error
NoticeValidationErrorResponse - 401Unauthorized
NoticeUnauthorizedResponse - 403Forbidden — missing required scope
NoticeUnauthorizedResponse - 404Notice not found in caller's tenant
NoticeNotFoundResponse - 429Rate limit exceeded
NoticeRateLimitResponse
POST/api/notices/{id}/entity-match-resolveResolve fuzzy entity match
Resolve a fuzzy entity-match candidate set for a notice. `action=confirmed` assigns the notice to an existing entity (verified to belong to caller's tenant). `action=create_new` creates a new entity in the notice's tenant and assigns the notice to it.
notices.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Notice UUID |
Request body NoticeEntityMatchResolveBodyrequired
application/json
Responses
- 200Resolved
NoticeEntityMatchResolveResponseField Type Required Description successenum: truerequired — entity_idstring · uuidrequired — actionenum: "confirmed" | "create_new"required — entity_namestringoptional — - 400Validation error
NoticeValidationErrorResponse - 401Unauthorized
NoticeUnauthorizedResponse - 403Forbidden — missing required scope
NoticeUnauthorizedResponse - 404Notice or resolved entity not found in caller's tenant
NoticeNotFoundResponse - 429Rate limit exceeded
NoticeRateLimitResponse
GET/api/notices/{id}/similarFind similar resolved notices
Find anonymized resolution patterns + similar resolved notices for a given notice. The source notice lookup is tenant-scoped; the pattern + outcomes lookups are intentionally cross-tenant (anonymized aggregate, no PII).
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Notice UUID |
Responses
- 200Resolution pattern + anonymized similar notices
NoticeSimilarResponseField Type Required Description patternResolutionPatternrequired — similar_countintegerrequired — similar_noticesarray<SimilarNotice>required — recommendationstringrequired — - 400Validation error
NoticeValidationErrorResponse - 401Unauthorized
NoticeUnauthorizedResponse - 403Forbidden — missing required scope
NoticeUnauthorizedResponse - 404Notice not found in caller's tenant
NoticeNotFoundResponse - 429Rate limit exceeded
NoticeRateLimitResponse
GET/api/notices/{id}/outcomeGet notice outcome
Returns the most recent recorded outcome for a notice (or null).
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Notice UUID |
Responses
- 200Outcome (or null)
NoticeOutcomeGetResponseField Type Required Description outcomeNoticeOutcomerequired — - 400Validation error
NoticeValidationErrorResponse - 401Unauthorized
NoticeUnauthorizedResponse - 403Forbidden — missing required scope
NoticeUnauthorizedResponse - 429Rate limit exceeded
NoticeRateLimitResponse
POST/api/notices/{id}/outcomeRecord notice outcome
Record the resolution outcome when a notice is resolved. Inserts a notice_outcomes row, optionally captures classification feedback, closes the notice, and aggregates into the cross-tenant resolution_patterns inventory for similar-notice recommendations.
notices.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Notice UUID |
Request body NoticeOutcomePostBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
resolution_type | string | required | — |
resolution_notes | string | optional | — |
resolution_method | string | optional | — |
corrected_type | string | optional | — |
original_amount | number | optional | — |
final_amount | number | optional | — |
documents_used | array<DocumentRef> | optional | — |
documents_missing | array<DocumentRef> | optional | — |
deadline_was_correct | boolean | optional | — |
actual_deadline | string · date | optional | — |
agency_response_date | string · date | optional | — |
Responses
- 200Outcome recorded
NoticeOutcomePostResponseField Type Required Description okenum: truerequired — outcome_idstring · uuidrequired — savingsnumberrequired — - 400Validation error
NoticeValidationErrorResponse - 401Unauthorized
NoticeUnauthorizedResponse - 403Forbidden — missing required scope
NoticeUnauthorizedResponse - 404Notice not found in caller's tenant
NoticeNotFoundResponse - 429Rate limit exceeded
NoticeRateLimitResponse
POST/api/notices/{id}/interpretInterpret notice PDF (Claude)
Synchronously interpret the notice PDF using Claude. Downloads the raw PDF, runs PII-redacted extraction + classification, validates against quality gates (returns 422 if they fail), creates artifact + lineage records, and updates the notice with the result.
notices.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Notice UUID |
Responses
- 200Interpreted
NoticeInterpretResponseField Type Required Description okenum: truerequired — noticeIdstring · uuidrequired — artifactIdstring · uuidrequired — interpretationobjectrequired — qualityCheckobjectrequired — metadataobjectrequired — - 400Validation error / no storage path / PDF interpretation failed
NoticeValidationErrorResponse - 401Unauthorized
NoticeUnauthorizedResponse - 403Forbidden — missing required scope
NoticeUnauthorizedResponse - 404Notice not found in caller's tenant
NoticeNotFoundResponse - 422Quality gates failed (interpretation incomplete)
NoticeInterpretQualityFailResponse - 429Rate limit exceeded
NoticeRateLimitResponse
POST/api/notices/classifyClassify notice text/file
Classify a notice from raw text (JSON body) or file upload (multipart/form-data). Runs PII redaction first, then LLM classification with a 15-second timeout. Cookie-session callers go through the Stripe subscription gate; Bearer-key callers do not.
notices.writeRequest body NoticeClassifyJsonBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
text | string | optional | — |
entity_id | string · uuid | optional | — |
Responses
- 200Classification result
NoticeClassifyResponseField Type Required Description notice_typestringrequired — jurisdictionstringoptional — deadlinestring · dateoptional — severitystringoptional — confidencenumberrequired — categorystringoptional — subcategorystringoptional — extracted_factsobjectrequired — enrichmentobjectrequired — - 400Validation error
NoticeValidationErrorResponse - 401Unauthorized
NoticeUnauthorizedResponse - 402Subscription required (cookie-session callers only)
NoticeUnauthorizedResponse - 403Forbidden — missing required scope
NoticeUnauthorizedResponse - 429Rate limit exceeded
NoticeRateLimitResponse - 500Server error / classification timeout
NoticeUnauthorizedResponse
GET/api/notices/{id}/draftGet notice draft
Returns the latest resolution draft for a notice (resolution_drafts preferred, falls back to response_drafts, then to inline draft on notices.extracted_json). Tenant-scoped.
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Notice UUID |
Responses
- 200Latest draft + evidence package
NoticeDraftGetResponseField Type Required Description draftNoticeDraftRecordrequired — evidence_packageNoticeEvidencePackagerequired — notice_deadlinestring · daterequired — sourceenum: "resolution_drafts" | "response_drafts" | "extracted_json"required — - 400Validation error
NoticeValidationErrorResponse - 401Unauthorized
NoticeUnauthorizedResponse - 403Forbidden — missing required scope
NoticeUnauthorizedResponse - 404Notice or draft not found in caller's tenant
NoticeNotFoundResponse - 429Rate limit exceeded
NoticeRateLimitResponse
POST/api/notices/{id}/draftGenerate notice draft
Generate a new draft via the pipeline draft generator. Cookie-session callers go through the Stripe subscription gate; Bearer-key callers do not.
notices.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Notice UUID |
Responses
- 200Draft generated
NoticeDraftPostResponseField Type Required Description draftNoticeDraftRecordrequired — evidence_packageNoticeEvidencePackagerequired — - 400Validation error
NoticeValidationErrorResponse - 401Unauthorized
NoticeUnauthorizedResponse - 402Subscription required (cookie-session callers only)
NoticeUnauthorizedResponse - 403Forbidden — missing required scope
NoticeUnauthorizedResponse - 404Notice not found in caller's tenant
NoticeNotFoundResponse - 429Rate limit exceeded
NoticeRateLimitResponse - 500Server error / draft generation failed
NoticeUnauthorizedResponse
PATCH/api/notices/{id}/draftUpdate notice draft
Update the most recent draft's content. Tenant-scoped both on read and update — root-cause fix vs pre-Phase-4 which only filtered by id.
notices.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Notice UUID |
Request body NoticeDraftPatchBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
content | string | required | — |
Responses
- 200Draft updated
NoticeDraftPatchResponseField Type Required Description draftNoticeDraftRecordrequired — - 400Validation error
NoticeValidationErrorResponse - 401Unauthorized
NoticeUnauthorizedResponse - 403Forbidden — missing required scope
NoticeUnauthorizedResponse - 404No draft found in caller's tenant
NoticeNotFoundResponse - 429Rate limit exceeded
NoticeRateLimitResponse
GET/api/notices/{id}/resolution-packageGet notice resolution package
Returns the most recent resolution package for a notice (or a stub when none has been generated). Tenant-scoped.
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Notice UUID |
Responses
- 200Existing package or 'not_generated' stub
ResolutionPackageGetResponseField Type Required Description package_idstring · uuidrequired — statusstringrequired — submission_methodstringoptional — submitted_atstring · date-timeoptional — metadataobjectoptional — documentsarray<ResolutionPackageDocument>required — - 400Validation error
NoticeValidationErrorResponse - 401Unauthorized
NoticeUnauthorizedResponse - 403Forbidden — missing required scope
NoticeUnauthorizedResponse - 429Rate limit exceeded
NoticeRateLimitResponse
POST/api/notices/{id}/resolution-packageGenerate notice resolution package
Generate a resolution package after confirming all required documents are present. Returns 400 if any are missing. If `protest_recommended` on the notice, generates a protest letter via Claude (PII-redacted) and bundles evidence; otherwise generates a `verification_complete` summary. Creates a submissions row and updates notice status.
notices.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Notice UUID |
Responses
- 200Package generated
ResolutionPackagePostResponseField Type Required Description package_idstring · uuidrequired — statusenum: "generated"required — package_typeenum: "protest_letter" | "verification_complete"required — documentsarray<ResolutionPackageDocument>required — - 400Validation error / required documents missing
NoticeValidationErrorResponse - 401Unauthorized
NoticeUnauthorizedResponse - 403Forbidden — missing required scope
NoticeUnauthorizedResponse - 404Notice or entity not found in caller's tenant
NoticeNotFoundResponse - 429Rate limit exceeded
NoticeRateLimitResponse - 500Server error
NoticeUnauthorizedResponse
GET/api/notices/{id}/detailGet notice detail
Returns the full notice + associated entity + audit_events + pipeline events + signed document URL + payroll context. Auto-applies any existing entity-level payroll verification when the tax year matches (re-uses prior payroll uploads across notices for the same entity).
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Notice UUID |
Responses
- 200Notice detail bundle
NoticeDetailResponseField Type Required Description noticeobjectrequired — entityobjectrequired — cpa_membersarray<object>required — eventsarray<object>required — pipeline_eventsarray<object>required — document_urlstringrequired — payrollobjectrequired — entity_payrollobjectrequired — - 400Validation error
NoticeValidationErrorResponse - 401Unauthorized
NoticeUnauthorizedResponse - 403Forbidden — missing required scope
NoticeUnauthorizedResponse - 404Notice not found in caller's tenant
NoticeNotFoundResponse - 429Rate limit exceeded
NoticeRateLimitResponse
POST/api/notices/{id}/detailAdd note to notice timeline
Append a note to the notice's audit timeline. Tenant_id always sourced from the auth context — never from the body — to prevent cross-tenant audit writes (Gemini PR #471 review fix).
notices.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Notice UUID |
Request body NoticeDetailPostBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
note | string | required | — |
Responses
- 200Note appended
NoticeOkResponseField Type Required Description okenum: truerequired — - 400Validation error
NoticeValidationErrorResponse - 401Unauthorized
NoticeUnauthorizedResponse - 403Forbidden — missing required scope
NoticeUnauthorizedResponse - 404Notice not found in caller's tenant
NoticeNotFoundResponse - 429Rate limit exceeded
NoticeRateLimitResponse
PATCH/api/notices/{id}/detailUpdate notice status
Update the notice status. Tenant-scoped (root-cause fix vs pre-Phase-4 which only filtered by id).
notices.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Notice UUID |
Request body NoticeDetailPatchBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
status | string | required | — |
Responses
- 200Updated
NoticeOkResponseField Type Required Description okenum: truerequired — - 400Validation error
NoticeValidationErrorResponse - 401Unauthorized
NoticeUnauthorizedResponse - 403Forbidden — missing required scope
NoticeUnauthorizedResponse - 404Notice not found in caller's tenant
NoticeNotFoundResponse - 429Rate limit exceeded
NoticeRateLimitResponse
GET/api/notices/{id}/required-documentsGet required-documents checklist
Returns the document checklist required to resolve the notice. Each entry tagged status=uploaded | on_file | not_uploaded based on prior direct uploads, entity-level documents, payroll-on-file (tax-year + state matched), or existing payroll_verification.
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Notice UUID |
Responses
- 200Checklist + per-doc status
RequiredDocumentsGetResponseField Type Required Description notice_typestringrequired — payroll_neededbooleanrequired — descriptionstringoptional — documentsarray<RequiredDocument>required — all_uploadedbooleanrequired — can_generate_resolutionbooleanrequired — - 400Validation error
NoticeValidationErrorResponse - 401Unauthorized
NoticeUnauthorizedResponse - 403Forbidden — missing required scope
NoticeUnauthorizedResponse - 404Notice not found in caller's tenant
NoticeNotFoundResponse - 429Rate limit exceeded
NoticeRateLimitResponse
POST/api/notices/{id}/required-documentsUpload checklist document
Upload a document for a checklist requirement. multipart/form-data with `file` + `document_key`. Payroll spreadsheets (CSV/XLSX) trigger the 4-path side-effect pipeline: PATH A rate verification, PATH B balance/payroll verification, PATH C ADP per-employee SUI, PATH D smart verification + auto-protest letter generation. All side effects are tenant-scoped (KRT-1479 P4b.7 root-cause fix).
notices.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Notice UUID |
Request body RequiredDocumentsMultipartBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
file | string | required | Document file binary |
document_key | string | required | Checklist key, e.g., quarterly_sui_wages | quarterly_payroll_summary |
Responses
- 200Uploaded; checklist re-evaluated
RequiredDocumentsPostResponseField Type Required Description okenum: truerequired — document_idstring · uuidrequired — all_uploadedbooleanrequired — - 400Validation error / missing file or document_key
NoticeValidationErrorResponse - 401Unauthorized
NoticeUnauthorizedResponse - 403Forbidden — missing required scope
NoticeUnauthorizedResponse - 404Notice not found in caller's tenant
NoticeNotFoundResponse - 429Rate limit exceeded (uploads use the 10/min ceiling)
NoticeRateLimitResponse - 500Server error / storage upload / document insert failed
NoticeUnauthorizedResponse
GET/api/noticesList notices
List notices for the caller's tenant with filters / sort / pagination. Bearer keys gate via `notices.read`.
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
status | query | string | optional | — |
filter | query | enum: "needs_review" | "in_progress" | "overdue" | "resolved" | optional | — |
state | query | string | optional | — |
search | query | string | optional | — |
date_from | query | string | optional | — |
date_to | query | string | optional | — |
sort_by | query | string | optional | — |
sort_dir | query | string | optional | — |
page | query | integer | optional | — |
page_size | query | integer | optional | — |
limit | query | integer | optional | — |
Responses
- 200Notices
NoticesListResponseField Type Required Description noticesarray<NoticeListItem>required — totalintegerrequired — pageintegerrequired — page_sizeintegerrequired — - 401Unauthorized
MiscUnauthorizedResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
GET/api/notices/historical-finesHistorical fines analysis
Aggregated historical fines analysis with statute-of-limitations for the caller's tenant. Returns total fines, recoverable amounts, expiring counts, and per-state breakdown.
notices.readResponses
- 200Fines analysis
HistoricalFinesResponseField Type Required Description totalFinesnumberrequired — noticeCountintegerrequired — recoverableAmountnumberrequired — recoverableCountintegerrequired — expiringCountintegerrequired — expiredAmountnumberrequired — topAmountsarray<object>required — dateRangeobjectrequired — byStateobjectrequired — estimatedRecoveryobjectrequired — historicalReviewPurchasedbooleanrequired — - 401Unauthorized
MiscUnauthorizedResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
GET/api/notices/review-queueCPA review queue
CPA review queue ordered by deadline urgency. Notices in pipeline states NEEDS_REVIEW / READY_FOR_REVIEW / AWAITING_PAYROLL / VERIFIED. CPA-class roles only on cookie sessions; Bearer keys gate via `notices.read`.
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
limit | query | integer | optional | — |
offset | query | integer | optional | — |
financial_impact | query | string | optional | — |
Responses
- 200Review queue
ReviewQueueResponseField Type Required Description noticesarray<object>required — countintegerrequired — - 401Unauthorized
MiscUnauthorizedResponse - 403Forbidden — CPA access required
MiscUnauthorizedResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
POST/api/notices/{id}/actionCPA action on notice
CPA action on a reviewed notice (approve, dismiss, request revision). Triggers pipeline_status transition: approved→ACTIONED, dismissed→DISMISSED, revision_requested→NEEDS_REVIEW. CPA-class roles only on cookie sessions; Bearer keys gate via `notices.write`.
notices.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Notice UUID |
Request body NoticeActionBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
action | enum: "approved" | "dismissed" | "revision_requested" | required | — |
notes | string | optional | — |
Responses
- 200Action recorded
NoticeActionResponseField Type Required Description okenum: truerequired — pipeline_statusstringrequired — - 400Validation error
MiscValidationErrorResponse - 401Unauthorized
MiscUnauthorizedResponse - 403Forbidden — CPA access required
MiscUnauthorizedResponse - 404Notice not found
MiscNotFoundResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
GET/api/notices/{id}/eventsList notice pipeline events
Pipeline event audit trail for a notice.
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Notice UUID |
Responses
- 200Events
NoticeEventsListResponseField Type Required Description eventsarray<NoticeEvent>required — - 400Validation error
MiscValidationErrorResponse - 401Unauthorized
MiscUnauthorizedResponse - 404Notice not found
MiscNotFoundResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
POST/api/notices/{id}/eventsCreate notice pipeline event
Record a manual pipeline event on a notice (e.g. evidence_verified).
notices.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Notice UUID |
Request body NoticeEventCreateBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
event_type | string | required | — |
description | string | optional | — |
Responses
- 201Event recorded
NoticeEventCreateResponseField Type Required Description eventNoticeEventrequired — - 400Validation error
MiscValidationErrorResponse - 401Unauthorized
MiscUnauthorizedResponse - 404Notice not found
MiscNotFoundResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
POST/api/notices/{id}/generate-draftGenerate draft response
Manually trigger draft response generation for a notice. Cookie sessions go through the Stripe gate; Bearer keys bypass. Bearer scope: `notices.write`.
notices.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Notice UUID |
Responses
- 200Draft generated
GenerateDraftResponseField Type Required Description okenum: truerequired — draft_idstring · uuidrequired — draft_lengthintegerrequired — - 400Validation error
MiscValidationErrorResponse - 401Unauthorized
MiscUnauthorizedResponse - 402Subscription required (cookie-session callers only)
MiscUnauthorizedResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
POST/api/notices/{id}/processTrigger notice pipeline
Manually trigger the notice pipeline (re-classify, re-cross-reference, regenerate draft). CPA-class roles only on cookie sessions; Bearer keys gate via `notices.write`. Cookie sessions go through the Stripe gate.
notices.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Notice UUID |
Responses
- 200Pipeline complete
ProcessNoticeResponseField Type Required Description okenum: truerequired — pipelineobjectrequired — - 400Validation error
MiscValidationErrorResponse - 401Unauthorized
MiscUnauthorizedResponse - 402Subscription required (cookie-session callers only)
MiscUnauthorizedResponse - 403Forbidden — CPA access required
MiscUnauthorizedResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
POST/api/notices/{id}/process-with-payrollProcess notice with payroll
Triggers validate+draft pipeline after payroll has been uploaded (only valid from AWAITING_PAYROLL). Cookie sessions go through the Stripe gate. Bearer scope: `notices.write`.
notices.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Notice UUID |
Responses
- 200Pipeline complete
ProcessWithPayrollResponseField Type Required Description okenum: truerequired — resultobjectrequired — - 400Validation error / wrong pipeline state / no payroll
MiscValidationErrorResponse - 401Unauthorized
MiscUnauthorizedResponse - 402Subscription required (cookie-session callers only)
MiscUnauthorizedResponse - 404Notice not found
MiscNotFoundResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
GET/api/notices/{id}/payroll-comparisonPayroll vs notice rate comparison
Compare a notice's assigned SUI rate against the employer's actual payroll data (with wage-base caps + quarterly breakdown). Bearer keys gate via `notices.read`.
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Notice UUID |
Responses
- 200Comparison
PayrollComparisonResponseField Type Required Description notice_ratenumberrequired — actual_ratenumberrequired — rate_deltanumberrequired — estimated_overpaymentnumberrequired — quartersarray<object>required — wage_base_capnumberrequired — statestringrequired — tax_yearintegerrequired — - 401Unauthorized
MiscUnauthorizedResponse - 404Notice not found
MiscNotFoundResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
POST/api/notices/{id}/draft/advanceAdvance draft through approval chain
Advance the draft response through approval steps (reviewed → counter_signed → submitted). CPA-class roles only on cookie sessions; Bearer keys gate via `notices.write`.
notices.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Notice UUID |
Request body DraftAdvanceBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
step | enum: "reviewed" | "counter_signed" | "submitted" | required | — |
notes | string | optional | — |
Responses
- 200Draft advanced
DraftAdvanceResponseField Type Required Description successenum: truerequired — currentStepenum: "reviewed" | "counter_signed" | "submitted"required — - 400Validation error
MiscValidationErrorResponse - 401Unauthorized
MiscUnauthorizedResponse - 403Forbidden — CPA access required
MiscUnauthorizedResponse - 404Notice not found
MiscNotFoundResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
POST/api/notices/{id}/draft-feedbackSubmit draft feedback
Submit thumbs-up/thumbs-down feedback on a generated draft response. Used to train future draft generation. Bearer keys gate via `notices.write`.
notices.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Notice UUID |
Request body DraftFeedbackBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
draft_id | string · uuid | required | — |
rating | enum: "thumbs_up" | "thumbs_down" | required | — |
comment | string | optional | — |
Responses
- 200Feedback recorded
DraftFeedbackResponseField Type Required Description successenum: truerequired — - 400Validation error
MiscValidationErrorResponse - 401Unauthorized
MiscUnauthorizedResponse - 404Notice or draft not found
MiscNotFoundResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
POST/api/notices/{id}/confirm-sui-rateConfirm/override SUI rate
CPA confirms or overrides the ADP-sourced SUI rate. `confirm` marks the ADP rate as verified; `override` stores a CPA-corrected rate alongside the ADP original. Bearer keys gate via `notices.write`.
notices.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Notice UUID |
Request body ConfirmSuiRateBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
action | enum: "confirm" | "override" | required | — |
override_rate | number | optional | — |
Responses
- 200Rate confirmed/overridden
ConfirmSuiRateResponseField Type Required Description successenum: truerequired — actionenum: "confirmed" | "overridden"required — statestringrequired — ratenumberoptional — original_ratenumberoptional — overridden_ratenumberoptional — confirmed_bystring · uuidrequired — - 400Validation error / cannot determine state
MiscValidationErrorResponse - 401Unauthorized
MiscUnauthorizedResponse - 404Notice or SUI rate record not found
MiscNotFoundResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
POST/api/notices/{id}/fileMark notice filed
Mark a notice as filed with the agency (KRT-1476 Feature 1 AC5). Captures confirmation_number + filed_at. Auto two-step transition open|needs_review → in_progress → filed. Optimistic lock prevents double-file races. CPA-class roles only on cookie sessions; Bearer keys gate via `notices.write`.
notices.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Notice UUID |
Request body NoticeFileBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
confirmation_number | string | required | — |
notes | string | optional | — |
Responses
- 200Notice filed
NoticeFileResponseField Type Required Description okenum: truerequired — notice_idstring · uuidrequired — statusenum: "filed"required — confirmation_numberstringrequired — filed_atstring · date-timerequired — - 400Validation error
MiscValidationErrorResponse - 401Unauthorized
MiscUnauthorizedResponse - 403Forbidden — CPA access required
MiscUnauthorizedResponse - 404Notice not found
MiscNotFoundResponse - 409Already filed / closed / race lost
NoticeFileConflictResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
GET/api/notices/{id}/evidence/{type}Generate evidence PDF
Generate an evidence PDF for a protest package. type=payroll-summary or claims-history. Uploads to Supabase storage and returns a 1-hour signed URL when upload succeeds; falls back to direct PDF binary response when the upload fails (rare — non-fatal for the workflow).
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Notice UUID |
type | path | enum: "payroll-summary" | "claims-history" | required | Evidence type |
Responses
- 200Signed URL (or PDF binary on storage failure)
NoticeEvidenceResponseField Type Required Description urlstringrequired — filenamestringrequired — - 400Validation error
MiscValidationErrorResponse - 401Unauthorized
MiscUnauthorizedResponse - 404Notice not found
MiscNotFoundResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
POST/api/notices/{id}/verify-rateVerify SUI rate
Verify a notice's assigned SUI rate against the employer's payroll experience. If payroll data is incomplete, returns needsData=true + the list of required fields. Cookie sessions go through the Stripe gate. Bearer scope: `notices.write`.
notices.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Notice UUID |
Request body VerifyRateBody
| Field | Type | Required | Description |
|---|---|---|---|
totalBenefitCharges | number | optional | — |
totalContributions | number | optional | — |
totalTaxableWages | number | optional | — |
averageAnnualPayroll | number | optional | — |
yearsInBusiness | integer | optional | — |
employeeCount | integer | optional | — |
voluntaryContributions | number | optional | — |
Responses
- 200Rate verification result OR needsData prompt
one of (VerifyRateResultResponse · VerifyRateNeedsDataResponse) - 400Validation error / state not supported
MiscValidationErrorResponse - 401Unauthorized
MiscUnauthorizedResponse - 402Subscription required (cookie-session callers only)
MiscUnauthorizedResponse - 404Notice not found
MiscNotFoundResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
POST/api/notices/uploadUpload notice
Single-notice intake. Auto-matches/creates entity from extracted text, uploads to storage, creates notice + document records, fires the pipeline asynchronously. Cookie sessions go through Stripe gate + rate-limit + idempotency middleware. Bearer keys gate via `notices.write`.
notices.writeRequest body objectrequired
| Field | Type | Required | Description |
|---|---|---|---|
file | string · binary | required | — |
entity_id | string · uuid | optional | — |
Responses
- 200Uploaded (or duplicate)
NoticeUploadResponseField Type Required Description okenum: truerequired — notice_idstring · uuidrequired — document_idstring · uuidoptional — storage_pathstringoptional — content_hashstringrequired — duplicateenum: trueoptional — - 400Validation error
MiscValidationErrorResponse - 401Unauthorized
MiscUnauthorizedResponse - 402Subscription required (cookie-session callers only)
MiscUnauthorizedResponse - 403Entity not found / not accessible
MiscUnauthorizedResponse - 409Duplicate notice (already uploaded)
NoticeUploadDuplicateResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
POST/api/notices/bulk-uploadBulk upload historical notices
Bulk historical notice ingestion. Up to 50 files in one FormData. Runs OCR-only (no classification); creates notice records with pipeline_status='OCR_ONLY'. Cookie sessions go through the Stripe gate. Bearer scope: `notices.write`.
notices.writeRequest body objectrequired
| Field | Type | Required | Description |
|---|---|---|---|
files | array<string · binary> | required | — |
Responses
- 200Upload + OCR result
NoticeBulkUploadResponseField Type Required Description okenum: truerequired — uploadCountintegerrequired — ocrSuccessintegerrequired — ocrFailedintegerrequired — - 400Validation error
MiscValidationErrorResponse - 401Unauthorized
MiscUnauthorizedResponse - 402Subscription required (cookie-session callers only)
MiscUnauthorizedResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
GET/api/notices/{id}/cross-referenceCross-reference notice with payroll
Cross-reference notice against payroll data; runs SUI-specific analysis with state-by-state taxable wage bases + max rates when applicable. Returns needs_payroll_data:true when payroll data is missing for the relevant period (auto-falls-back to adjacent years). Persists cross_reference_analysis on the notice. Bearer keys gate via `notices.read`.
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Notice UUID |
Responses
- 200Result OR needs_payroll_data prompt
one of (CrossReferenceResultResponse · CrossReferenceNeedsDataResponse) - 401Unauthorized
MiscUnauthorizedResponse - 404Notice not found
MiscNotFoundResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
POST/api/notices/{id}/send-for-signatureSend notice response for signature
E-signature flow (KRT-1476 Feature 1 Phase 6): renders/uploads a response PDF if no document_id is provided, creates a signature_requests row with secure token + 7-day expiry, sends the signing-link email to the client. Returns signing_link + request_id even if email delivery fails (best-effort). CPA-class roles only on cookie sessions; Bearer keys gate via `notices.write`.
notices.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Notice UUID |
Request body SendForSignatureBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
signer_name | string | required | — |
signer_email | string · email | required | — |
signer_title | string | optional | — |
expires_days | integer | optional | — |
document_id | string · uuid | optional | — |
document_title | string | optional | — |
Responses
- 201Signature request created
SendForSignatureResponseField Type Required Description okenum: truerequired — signing_linkstringrequired — request_idstring · uuidrequired — secure_tokenstringrequired — expires_atstring · date-timerequired — document_idstring · uuidrequired — email_sentbooleanrequired — - 400Validation error
MiscValidationErrorResponse - 401Unauthorized
MiscUnauthorizedResponse - 403Forbidden — CPA access required
MiscUnauthorizedResponse - 404Notice or document not found
MiscNotFoundResponse - 409Notice already filed/closed OR document linked elsewhere
MiscValidationErrorResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
Packets4
GET/api/packets/{id}Get response packet
Get response packet with status + document list + linked notice metadata (KRT-224).
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Response packet UUID |
Responses
- 200Packet
PacketDetailResponseField Type Required Description okenum: truerequired — packetPacketDetailrequired — - 400Validation error
MiscValidationErrorResponse - 401Unauthorized
MiscUnauthorizedResponse - 404Packet not found
MiscNotFoundResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
GET/api/packets/{id}/downloadDownload response packet
Generate 7-day signed download URLs for all packet documents.
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Response packet UUID |
Responses
- 200Signed URLs
PacketDownloadResponseField Type Required Description okenum: truerequired — packet_idstring · uuidrequired — documentsarray<PacketDownloadDocument>required — expires_in_secondsintegerrequired — messagestringrequired — - 400Validation error
MiscValidationErrorResponse - 401Unauthorized
MiscUnauthorizedResponse - 404Packet or documents not found
MiscNotFoundResponse - 409Packet still assembling
MiscValidationErrorResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
POST/api/packets/{id}/submitSubmit response packet
Mark a response packet as submitted, record submission reference, and transition the linked notice to `filed` status. Refused unless packet is in `ready` state.
notices.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Response packet UUID |
Request body PacketSubmitBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
submission_ref | string | required | — |
submission_method | enum: "email" | "fax" | "portal" | "mail" | optional | — |
notes | string | optional | — |
Responses
- 200Submitted
PacketSubmitResponseField Type Required Description okenum: truerequired — packetobjectrequired — messagestringrequired — - 400Validation error
MiscValidationErrorResponse - 401Unauthorized
MiscUnauthorizedResponse - 404Packet not found
MiscNotFoundResponse - 409Packet not in ready status
MiscValidationErrorResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
POST/api/packets/assembleAssemble response packet
Trigger an async packet assembly job. Returns a job_id; poll the packet endpoint for status. Cookie sessions go through rate-limit + idempotency middleware.
notices.writeRequest body PacketAssembleBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
notice_id | string · uuid | required | — |
resolution_id | string · uuid | optional | — |
evidence_ids | array<string · uuid> | optional | — |
Responses
- 200Job queued
PacketAssembleResponseField Type Required Description okenum: truerequired — job_idstring · uuidrequired — notice_idstring · uuidrequired — statusenum: "assembling"required — messagestringrequired — - 400Validation error
MiscValidationErrorResponse - 401Unauthorized
MiscUnauthorizedResponse - 404Notice not found
MiscNotFoundResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
Payroll9
GET/api/payroll/dataGet payroll dropdown data
Returns entities visible to the caller, optionally with notices for a specific entity. Backs the payroll-page entity dropdown.
payroll.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
entity_id | query | string · uuid | optional | When present, also returns notices for this entity (tenant-scoped) |
Responses
- 200Entities + (optional) notices
PayrollDataResponseField Type Required Description entitiesarray<PayrollEntity>required — noticesarray<PayrollNoticeSummary>required — - 400Validation error
PayrollValidationErrorResponse - 401Unauthorized
PayrollUnauthorizedResponse - 403Forbidden — missing required scope
PayrollUnauthorizedResponse - 429Rate limit exceeded
PayrollRateLimitResponse
GET/api/payroll/template.csvDownload payroll CSV template
Returns a CSV template for payroll data upload. Columns match the generic format payroll-validator.ts expects.
payroll.readResponses
- 200CSV template
string - 401Unauthorized
- 403Forbidden — missing required scope
- 429Rate limit exceeded
POST/api/payroll/parse-previewPreview payroll file headers
Server-side payroll preview parser. Returns only the header row + row count for client-side column-mapping; the full file still ships to /api/payroll/upload for processing. Routes XLSX through the hardened safeParseXLSX wrapper (xlsx@0.18.5 has known CVEs that the wrapper neutralizes).
payroll.readRequest body PayrollMultipartFileBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
file | string | required | CSV or Excel binary |
Responses
- 200Header preview + row count
PayrollParsePreviewResponseField Type Required Description headersarray<string>required — rowCountintegerrequired — formatenum: "xlsx" | "csv"required — - 400Validation error / invalid file
PayrollValidationErrorResponse - 401Unauthorized
PayrollUnauthorizedResponse - 403Forbidden — missing required scope
PayrollUnauthorizedResponse - 413File too large (>10 MB)
PayrollValidationErrorResponse - 415Unsupported file type
PayrollValidationErrorResponse - 429Rate limit exceeded
PayrollRateLimitResponse
POST/api/payroll/validateValidate ADP payroll CSV
ADP payroll CSV validator (KRT-396). Accepts multipart with `file` + `notice_id`. Validates the CSV against the ADP-specific validator and persists the result to validation_results. Tenant-scoped on the notice access check + insert.
payroll.writeRequest body PayrollValidateMultipartBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
file | string | required | ADP CSV file |
notice_id | string · uuid | required | Notice UUID to validate against |
Responses
- 200Validation result + persisted record id
PayrollValidateResponseField Type Required Description okenum: truerequired — validation_result_idstring · uuidrequired — validationobjectrequired — - 400Validation error / file too large / not CSV
PayrollValidationErrorResponse - 401Unauthorized
PayrollUnauthorizedResponse - 403Forbidden — missing required scope
PayrollUnauthorizedResponse - 404Notice not found in caller's tenant
PayrollNotFoundResponse - 429Rate limit exceeded
PayrollRateLimitResponse - 500Server error
PayrollUnauthorizedResponse
GET/api/payroll/pullGet payroll data status
Returns the current payroll-data status for an entity — cache tier, age in days, and active provider connection (if any). All queries tenant-scoped.
payroll.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
entity_id | query | string · uuid | required | Employer entity UUID (required) |
Responses
- 200Status bundle
PayrollPullStatusResponseField Type Required Description connectionobjectrequired — payroll_dataobjectrequired — cache_tierenum: "hot" | "warm" | "cold" | "none"required — age_daysintegerrequired — - 400Validation error
PayrollValidationErrorResponse - 401Unauthorized
PayrollUnauthorizedResponse - 403Forbidden — missing required scope
PayrollUnauthorizedResponse - 429Rate limit exceeded
PayrollRateLimitResponse - 500Server error
PayrollUnauthorizedResponse
POST/api/payroll/pullTrigger payroll pull
Trigger a payroll pull for an employer entity. Routes through the tiered pull-engine cache (hot/warm/cold); `force_refresh=true` skips the hot tier. Returns 404 if no provider connection is configured.
payroll.writeRequest body PayrollPullPostBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
entity_id | string · uuid | required | — |
trigger_type | string | required | — |
trigger_ref | string | optional | — |
force_refresh | boolean | optional | — |
Responses
- 200Pull result
PayrollPullPostResponseField Type Required Description successenum: truerequired — cache_tierenum: "hot" | "warm" | "cold"required — employee_countintegerrequired — total_earningsnumberrequired — statesarray<string>required — pulled_atstring · date-timerequired — - 400Validation error
PayrollValidationErrorResponse - 401Unauthorized
PayrollUnauthorizedResponse - 403Forbidden — missing required scope
PayrollUnauthorizedResponse - 404No payroll data available — check employer connection
PayrollNotFoundResponse - 429Rate limit exceeded
PayrollRateLimitResponse - 500Server error
PayrollUnauthorizedResponse
POST/api/payroll/notice-syncADP credentialed payroll sync for a notice
Sync ADP payroll for a specific notice's quarter + 5 quarters of gap-fill. Credentials are stored temporarily in AWS SSM and deleted after the session unless `save_connection=true`. Plaintext NEVER persists outside SSM.
payroll.writeRequest body PayrollNoticeSyncBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
entity_id | string · uuid | required | — |
notice_id | string · uuid | required | — |
needed_year | integer | required | — |
needed_quarter | integer | required | — |
username | string | required | — |
password | string | required | — |
company_code | string | optional | — |
save_connection | boolean | optional | — |
Responses
- 200Sync result + per-period stats
PayrollNoticeSyncResponseField Type Required Description successbooleanrequired — notice_idstring · uuidrequired — notice_period_syncedbooleanrequired — gap_periods_syncedintegerrequired — total_employeesintegerrequired — total_wage_recordsintegerrequired — errorsarray<string>required — messagestringrequired — - 400Validation error
PayrollValidationErrorResponse - 401Unauthorized
PayrollUnauthorizedResponse - 403Forbidden — missing required scope
PayrollUnauthorizedResponse - 429Rate limit exceeded
PayrollRateLimitResponse - 500Server error / SSM / connection upsert failure
PayrollUnauthorizedResponse
POST/api/payroll/upload-reportUpload payroll report
Upload a payroll-related report file (CSV/PDF/Excel) for an entity. Persists to documents + Supabase storage. CSVs additionally get parsed and the parsed summary stored on the document row for downstream rate verification.
payroll.writeRequest body PayrollUploadReportMultipartBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
file | string | required | CSV/PDF/Excel binary (max 50 MB) |
report_type | string | required | Normalized report type (e.g., payroll_journal) |
entity_id | string · uuid | required | — |
Responses
- 200Uploaded; document_id + parsed summary (CSV only)
PayrollUploadReportResponseField Type Required Description successenum: truerequired — documentIdstring · uuidrequired — fileUrlstringrequired — storage_pathstringrequired — content_hashstringrequired — parsedobjectrequired — - 400Validation error
PayrollValidationErrorResponse - 401Unauthorized
PayrollUnauthorizedResponse - 403Forbidden — missing required scope
PayrollUnauthorizedResponse - 404Entity not found in caller's tenant
PayrollNotFoundResponse - 429Rate limit exceeded (uploads use the 10/min ceiling)
PayrollRateLimitResponse - 500Server error / storage upload / document insert failed
PayrollUnauthorizedResponse
POST/api/payroll/uploadUpload payroll file (heavy)
Upload a payroll CSV or Excel file for an entity, optionally linked to a notice. Pipeline: storage upload → payroll_uploads + payroll_records insert → SUI detail extraction (per-employee/month/state from Excel) → mergePayrollData into entity_payroll_data → validation_results when notice-linked → auto-trigger verification pipeline for AWAITING_PAYROLL notices. Idempotency-aware: same x-idempotency-key replays the prior response.
payroll.writeRequest body PayrollUploadFormBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
file | string | required | CSV or Excel binary (max 10 MB) |
entity_id | string · uuid | required | — |
notice_id | string · uuid | optional | — |
column_map | string | optional | JSON-stringified ColumnMap (employee_name, gross_wages, state, etc.) |
Responses
- 200Uploaded; validation summary + records_stored count
PayrollUploadResponseDetailedField Type Required Description okenum: truerequired — payroll_upload_idstring · uuidrequired — storage_pathstringrequired — content_hashstringrequired — validationPayrollUploadValidationSummaryrequired — records_storedintegerrequired — - 400Validation error / file too large / unsupported file type / unsafe XLSX
PayrollValidationErrorResponse - 401Unauthorized
PayrollUnauthorizedResponse - 402Subscription required (cookie-session callers only)
PayrollUnauthorizedResponse - 403Forbidden — missing required scope
PayrollUnauthorizedResponse - 404Entity or notice not found in caller's tenant
PayrollNotFoundResponse - 429Rate limit exceeded (uploads use the 10/min ceiling)
PayrollRateLimitResponse - 500Server error / storage / validation pipeline failure
PayrollUnauthorizedResponse
POA7
GET/api/poa-authorizationsList POA authorizations
List POA authorizations for the caller's tenant (KRT-464). Filter by employer_entity_id / poa_entity_id; toggle inclusion of revoked rows with `include_revoked=true`. Bearer keys gate via `notices.read`.
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
employer_entity_id | query | string · uuid | optional | — |
poa_entity_id | query | string · uuid | optional | — |
include_revoked | query | boolean | optional | — |
Responses
- 200POA authorizations
POAAuthorizationsListResponseField Type Required Description authorizationsarray<POAAuthorization>required — - 401Unauthorized
MiscUnauthorizedResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
POST/api/poa-authorizationsRequest POA authorization
Request a new POA authorization (KRT-464). 409 if an authorization already exists for the same employer + poa + scope. Bearer keys gate via `notices.write`.
notices.writeRequest body POAAuthorizationCreateBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
employer_entity_id | string · uuid | required | — |
poa_entity_id | string · uuid | required | — |
scope | array<POAScope> | required | — |
Responses
- 201Authorization requested
POAAuthorizationCreateResponseField Type Required Description authorizationPOAAuthorizationrequired — - 400Validation error
MiscValidationErrorResponse - 401Unauthorized
MiscUnauthorizedResponse - 409Authorization already exists
MiscValidationErrorResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
POST/api/poa-authorizations/{id}/generateGenerate pre-filled POA PDF
Generate a pre-filled POA PDF for a previously-created authorization. Two modes: `download` (returns the PDF + filing instructions only) and `send-for-signature` (creates a signature_request and emails the signer + a copy to the originating CPA). Bearer keys gate via `notices.write`. Kreto does NOT submit the form to the agency — the user files manually using the agency portal or mailing address in the `filing` block of the response.
notices.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | POA authorization UUID |
Request body POAGenerateBody
| Field | Type | Required | Description |
|---|---|---|---|
template_id | string | required | Pre-auth template id (e.g., 'poa-tax-representation'). Browse via GET /api/pre-authorization-templates. |
mode | enum: "download" | "send-for-signature" | optional | 'download' returns the PDF only. 'send-for-signature' creates a signature_request, emails the signer + originator. Default: send-for-signature. |
signer_name | string | optional | — |
signer_email | string · email | optional | — |
overrides | object | optional | — |
Responses
- 200Mode=download: pre-filled PDF + filing instructions
objectField Type Required Description modeenum: "download"required — authorization_idstring · uuidrequired — template_idstringrequired — template_namestringrequired — document_pathstringrequired — document_urlstringrequired — document_hashstringrequired — filingobjectrequired — missing_required_fieldsarray<string>required — - 201Mode=send-for-signature: signing request created + email queued
objectField Type Required Description modeenum: "send-for-signature"required — authorization_idstring · uuidrequired — signature_request_idstring · uuidrequired — secure_tokenstringrequired — signing_linkstringrequired — expires_atstring · date-timerequired — document_pathstringrequired — document_urlstringrequired — document_hashstringrequired — template_idstringrequired — template_namestringrequired — filingobjectrequired — missing_required_fieldsarray<string>required — signer_emailstring · emailrequired — originator_emailedbooleanrequired — - 400Validation error (missing template_id, invalid body, etc.)
MiscValidationErrorResponse - 401Unauthorized
MiscUnauthorizedResponse - 404Authorization or employer entity not found in your tenant
MiscNotFoundResponse - 409Authorization is revoked — cannot generate a document
MiscValidationErrorResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error (PDF generation failure, DB error)
MiscUnauthorizedResponse
PATCH/api/poa-authorizations/{id}Revoke POA authorization
Revoke a POA authorization. Bearer keys gate via `notices.write`. 409 if already revoked.
notices.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | POA authorization UUID |
Responses
- 200Authorization revoked
POAAuthorizationRevokeResponseField Type Required Description authorizationPOAAuthorizationrequired — - 400Validation error
MiscValidationErrorResponse - 401Unauthorized
MiscUnauthorizedResponse - 404Authorization not found
MiscNotFoundResponse - 409Authorization already revoked
MiscValidationErrorResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
GET/api/pre-authorization-templatesList pre-auth templates
List pre-authorization templates from the global Kreto library. No tenant data is read. Bearer keys gate via `notices.read`.
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
category | query | string | optional | — |
state | query | string | optional | — |
Responses
- 200Templates
PreAuthTemplatesListResponseField Type Required Description templatesarray<PreAuthTemplateSummary>required — totalintegerrequired — - 401Unauthorized
MiscUnauthorizedResponse - 429Rate limit exceeded
MiscRateLimitResponse
GET/api/pre-authorization-templates/{id}Get pre-auth template
Retrieve full template details (content template + field definitions + signature fields). Bearer keys gate via `notices.read`.
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | required | Pre-auth template ID |
Responses
- 200Template
PreAuthTemplateDetailResponseField Type Required Description templatePreAuthTemplateFullrequired — - 401Unauthorized
MiscUnauthorizedResponse - 404Template not found
MiscNotFoundResponse - 429Rate limit exceeded
MiscRateLimitResponse
POST/api/pre-authorization-templates/{id}/autofillAuto-fill pre-auth template
Auto-fill a pre-authorization template from entity data. Optionally renders to PDF and uploads to storage when generate_pdf=true (and employer_id is provided). CPA-class roles only on cookie sessions; Bearer keys gate via `notices.write`.
notices.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | required | Pre-auth template ID |
Request body PreAuthAutofillBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
entity_data | object | required | — |
overrides | object | optional | — |
generate_pdf | boolean | optional | — |
employer_id | string · uuid | optional | — |
cpa_name | string | optional | — |
cpa_firm | string | optional | — |
Responses
- 200Auto-fill result (with optional pdf_path/pdf_hash)
PreAuthAutofillResponseField Type Required Description rendered_contentstringrequired — resolved_fieldsobjectrequired — missing_required_fieldsarray<string>required — missing_optional_fieldsarray<string>required — pdf_pathstringoptional — pdf_hashstringoptional — - 400Validation error
MiscValidationErrorResponse - 401Unauthorized
MiscUnauthorizedResponse - 403Forbidden — CPA access required
MiscUnauthorizedResponse - 404Template not found
MiscNotFoundResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
Reports7
GET/api/reports/notice-summaryNotice summary report
Group notices by status + (primary) type for the caller's tenant. Bearer keys gate via `notices.read`.
notices.readResponses
- 200Summary
ReportsNoticeSummaryResponseField Type Required Description by_statusobjectrequired — by_typeobjectrequired — totalintegerrequired — - 401Unauthorized
ReportsUnauthorizedResponse - 429Rate limit exceeded
ReportsRateLimitResponse - 500Server error
ReportsUnauthorizedResponse
GET/api/reports/roiROI report
ROI metrics: total savings, notices resolved, average resolution days, protests won, and ROI multiple. Bearer keys gate via `notices.read`.
notices.readResponses
- 200ROI
ReportsRoiResponseField Type Required Description total_savingsnumberrequired — notices_resolvedintegerrequired — avg_resolution_daysintegerrequired — protests_wonintegerrequired — roi_multiplenumberrequired — - 401Unauthorized
ReportsUnauthorizedResponse - 429Rate limit exceeded
ReportsRateLimitResponse - 500Server error
ReportsUnauthorizedResponse
GET/api/reports/sui-impactSUI impact report
SUI-related notice analysis with per-notice breakdown. Bearer keys gate via `notices.read`.
notices.readResponses
- 200SUI impact
ReportsSuiImpactResponseField Type Required Description summaryobjectrequired — noticesarray<ReportsSuiImpactNotice>required — - 401Unauthorized
ReportsUnauthorizedResponse - 429Rate limit exceeded
ReportsRateLimitResponse - 500Server error
ReportsUnauthorizedResponse
GET/api/reports/compliance-scorecardCompliance scorecard
Entity-level compliance scores + trend signal (+5 / 0 / -5). Bearer keys gate via `notices.read`.
notices.readResponses
- 200Scorecard
ReportsScorecardResponseField Type Required Description entitiesarray<ReportsScorecardEntity>required — - 401Unauthorized
ReportsUnauthorizedResponse - 429Rate limit exceeded
ReportsRateLimitResponse - 500Server error
ReportsUnauthorizedResponse
GET/api/reports/state-authorizationState authorization report
POA status per entity per state, joining poa_authorizations + documents tables. Bearer keys gate via `notices.read`.
notices.readResponses
- 200State authorization
ReportsStateAuthResponseField Type Required Description entitiesarray<ReportsStateAuthEntity>required — - 401Unauthorized
ReportsUnauthorizedResponse - 429Rate limit exceeded
ReportsRateLimitResponse - 500Server error
ReportsUnauthorizedResponse
GET/api/reports/response-timeResponse-time report
Notice processing-time metrics (classification seconds, resolution days, draft hours) with monthly breakdown. Bearer keys gate via `notices.read`.
notices.readResponses
- 200Response-time metrics
ReportsResponseTimeResponseField Type Required Description avg_classification_secondsintegerrequired — avg_resolution_daysnumberrequired — avg_draft_hoursnumberrequired — total_processedintegerrequired — by_montharray<ReportsResponseTimeMonth>required — - 401Unauthorized
ReportsUnauthorizedResponse - 429Rate limit exceeded
ReportsRateLimitResponse - 500Server error
ReportsUnauthorizedResponse
POST/api/reports/generateGenerate report
Generate a compliance report for the requested entities + date range. Returns JSON or a CSV file (Content-Disposition: attachment). Up to 50 entities per call. Bearer keys gate via `audit.read` (full tenant scope); cookie sessions use RLS-enforced entity access.
audit.readRequest body ReportsGenerateBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
type | string | required | — |
entityIds | array<string · uuid> | required | — |
dateRange | object | required | — |
format | enum: "json" | "csv" | optional | — |
Responses
- 200Report (JSON when format=json; CSV download otherwise)
ReportsGenerateJsonResponseField Type Required Description typestringrequired — rowsarray<object>required — summaryobjectoptional — csvstringoptional — - 400Validation error
ReportsValidationErrorResponse - 401Unauthorized
ReportsUnauthorizedResponse - 403Access denied for one or more entityIds
ReportsUnauthorizedResponse - 429Rate limit exceeded
ReportsRateLimitResponse - 500Server error
ReportsUnauthorizedResponse
Resolutions5
POST/api/resolutions/generateGenerate resolution draft
Generate a resolution draft via Claude. CPA-only on cookie sessions; Bearer keys gate via `notices.write`. PII redacted before LLM call. Idempotency-aware via x-idempotency-key.
notices.writeRequest body ResolutionGenerateBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
notice_id | string · uuid | required | — |
evidence_id | string · uuid | required | — |
template | ResolutionTemplate | required | — |
discrepancies | array<ResolutionDiscrepancy> | optional | — |
additional_context | string | optional | — |
Responses
- 200Draft generated
ResolutionGenerateResponseField Type Required Description okenum: truerequired — draft_idstring · uuidrequired — versionintegerrequired — statusenum: "draft"required — redacted_fieldsarray<string>required — - 400Validation error
ResolutionValidationErrorResponse - 401Unauthorized
ResolutionUnauthorizedResponse - 402Subscription required (cookie-session callers only)
ResolutionUnauthorizedResponse - 403Forbidden — CPA access required / missing scope
ResolutionUnauthorizedResponse - 404Notice or evidence packet not found in caller's tenant
ResolutionNotFoundResponse - 429Rate limit exceeded
ResolutionRateLimitResponse - 500Server error
ResolutionUnauthorizedResponse
GET/api/resolutions/{id}Get resolution draft
Returns the draft + joined evidence packet metadata + tenant status counts. 422 if draft has no evidence packet (data integrity).
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Resolution draft UUID |
Responses
- 200Draft + evidence + stats
ResolutionGetResponseField Type Required Description okenum: truerequired — draftall of (ResolutionDraftRecord · object)required — statsobjectrequired — - 400Validation error
ResolutionValidationErrorResponse - 401Unauthorized
ResolutionUnauthorizedResponse - 403Forbidden — missing required scope
ResolutionUnauthorizedResponse - 404Draft not found in caller's tenant
ResolutionNotFoundResponse - 422Draft missing evidence packet (data integrity)
ResolutionValidationErrorResponse - 429Rate limit exceeded
ResolutionRateLimitResponse - 500Server error
ResolutionUnauthorizedResponse
PATCH/api/resolutions/{id}Edit resolution draft (CPA)
CPA edits draft text. Only allowed in `draft` or `in_review` status.
notices.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Resolution draft UUID |
Request body ResolutionPatchBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
cpa_edits | string | required | — |
status | enum: "in_review" | optional | — |
Responses
- 200Draft updated
ResolutionPatchResponseField Type Required Description okenum: truerequired — draft_idstring · uuidrequired — statusstringrequired — - 400Validation error / draft in non-editable status
ResolutionValidationErrorResponse - 401Unauthorized
ResolutionUnauthorizedResponse - 403Forbidden — CPA access required
ResolutionUnauthorizedResponse - 404Draft not found in caller's tenant
ResolutionNotFoundResponse - 429Rate limit exceeded
ResolutionRateLimitResponse - 500Server error
ResolutionUnauthorizedResponse
POST/api/resolutions/{id}/approveApprove resolution draft (CPA)
CPA approves a resolution draft. Status transitions in_review → approved. Only valid from in_review.
notices.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Resolution draft UUID |
Request body ResolutionApproveBody
| Field | Type | Required | Description |
|---|---|---|---|
notes | string | optional | — |
Responses
- 200Approved
ResolutionApproveResponseField Type Required Description okenum: truerequired — draft_idstring · uuidrequired — statusenum: "approved"required — - 400Validation error / wrong status
ResolutionValidationErrorResponse - 401Unauthorized
ResolutionUnauthorizedResponse - 403Forbidden — CPA access required
ResolutionUnauthorizedResponse - 404Draft not found in caller's tenant
ResolutionNotFoundResponse - 429Rate limit exceeded
ResolutionRateLimitResponse - 500Server error
ResolutionUnauthorizedResponse
POST/api/resolutions/{id}/rejectReject resolution draft (CPA)
CPA rejects a draft (in_review → rejected) and optionally regenerates a fresh draft with rejection feedback. Returns new_draft_id when regeneration succeeds.
notices.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Resolution draft UUID |
Request body ResolutionRejectBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
rejection_reason | string | required | — |
regenerate | boolean | optional | — |
Responses
- 200Rejected
ResolutionRejectResponseField Type Required Description okenum: truerequired — draft_idstring · uuidrequired — statusenum: "rejected"required — new_draft_idstring · uuidrequired — - 400Validation error / wrong status
ResolutionValidationErrorResponse - 401Unauthorized
ResolutionUnauthorizedResponse - 403Forbidden — CPA access required
ResolutionUnauthorizedResponse - 404Draft not found in caller's tenant
ResolutionNotFoundResponse - 429Rate limit exceeded
ResolutionRateLimitResponse - 500Server error
ResolutionUnauthorizedResponse
Settings2
GET/api/settings/firmGet firm settings
Firm/tenant settings (name, slug). Bearer keys gate via `admin.read`.
admin.readResponses
- 200Settings
SettingsFirmResponseField Type Required Description namestringrequired — slugstringrequired — created_atstring · date-timerequired — - 401Unauthorized
MiscUnauthorizedResponse - 404Tenant not found
MiscNotFoundResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
PATCH/api/settings/firmUpdate firm settings
Update firm/tenant settings (currently: name only). Bearer keys gate via `admin.read`.
admin.readRequest body SettingsFirmUpdateBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
name | string | required | — |
Responses
- 200Settings updated
SettingsFirmResponseField Type Required Description namestringrequired — slugstringrequired — created_atstring · date-timerequired — - 400Validation error
MiscValidationErrorResponse - 401Unauthorized
MiscUnauthorizedResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
SIDES10
GET/api/sides/enrollmentsList SIDES enrollments
List all SIDES employer enrollments for the caller's tenant. CPA-class roles only on cookie sessions; Bearer keys gate via `notices.read`.
notices.readResponses
- 200Enrollments
SidesEnrollmentsListResponseField Type Required Description enrollmentsarray<SidesEnrollment>required — - 401Unauthorized
SidesUnauthorizedResponse - 403Forbidden — CPA access required
SidesUnauthorizedResponse - 429Rate limit exceeded
SidesRateLimitResponse - 500Server error
SidesUnauthorizedResponse
POST/api/sides/enrollmentsEnroll employer in SIDES
Enroll an employer in SIDES for a specific state. NASWA admin-site enrollment is tracked locally; status starts as `pending`. CPA-class roles only on cookie sessions; Bearer keys gate via `notices.write`.
notices.writeRequest body SidesEnrollmentCreateBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
entity_id | string · uuid | required | — |
state_code | string | required | — |
employer_account_number | string | optional | — |
Responses
- 201Enrollment created
SidesEnrollmentCreateResponseField Type Required Description enrollmentSidesEnrollmentrequired — - 400Validation error
SidesValidationErrorResponse - 401Unauthorized
SidesUnauthorizedResponse - 403Forbidden — CPA access required
SidesUnauthorizedResponse - 404Entity not found
SidesNotFoundResponse - 409Already enrolled in this state
SidesValidationErrorResponse - 429Rate limit exceeded
SidesRateLimitResponse - 500Server error
SidesUnauthorizedResponse
GET/api/sides/exchangesList SIDES exchanges
List inbound SIDES exchanges for the caller's tenant. Supports status / exchange_type / state_code filters, pagination, and sort. Any authenticated caller can read. Bearer keys gate via `notices.read`.
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
status | query | string | optional | — |
exchange_type | query | string | optional | — |
state_code | query | string | optional | — |
sort | query | enum: "due_date" | "received_date" | "status" | optional | — |
limit | query | integer | optional | — |
offset | query | integer | optional | — |
Responses
- 200Exchanges + total
SidesExchangesListResponseField Type Required Description exchangesarray<SidesExchangeListItem>required — totalintegerrequired — limitintegerrequired — offsetintegerrequired — - 400Validation error
SidesValidationErrorResponse - 401Unauthorized
SidesUnauthorizedResponse - 429Rate limit exceeded
SidesRateLimitResponse - 500Server error
SidesUnauthorizedResponse
GET/api/sides/exchanges/{id}Get SIDES exchange
Fetch a single SIDES exchange + audit log. Any authenticated caller can read; cookie sessions with `client_user` role get a PII-reduced view (raw XML payloads + claimant names stripped). Bearer keys gate via `notices.read` and receive the full payload.
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | SIDES exchange / claim UUID |
Responses
- 200Exchange + audit log
SidesExchangeDetailResponseField Type Required Description exchangeobjectrequired — audit_logarray<SidesAuditEntry>required — - 401Unauthorized
SidesUnauthorizedResponse - 404Exchange not found
SidesNotFoundResponse - 429Rate limit exceeded
SidesRateLimitResponse - 500Server error
SidesUnauthorizedResponse
PUT/api/sides/exchanges/{id}Save SI draft response
Save a drafted SI response for an exchange. Validates via Zod and serializes to XML when valid; otherwise stashes the JSON body for round-trip editing. CPA-class roles only on cookie sessions; Bearer keys gate via `notices.write`.
notices.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | SIDES exchange / claim UUID |
Request body SidesSaveDraftBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
response | object | required | — |
Responses
- 200Draft saved
SidesSaveDraftResponseField Type Required Description okenum: truerequired — validbooleanrequired — errorsarray<object>required — - 400Validation error / unsupported exchange type
SidesValidationErrorResponse - 401Unauthorized
SidesUnauthorizedResponse - 403Forbidden — CPA access required
SidesUnauthorizedResponse - 404Exchange not found
SidesNotFoundResponse - 429Rate limit exceeded
SidesRateLimitResponse - 500Server error
SidesUnauthorizedResponse
POST/api/sides/exchanges/{id}/submitSubmit SI response (CPA)
Approve and submit an SI response to the SIDES Central Broker. The server injects claimantSSNLast4 from the original request XML, validates, serializes, and posts via the NASWA Model Connector CLI. Re-submit is rejected (409) once an exchange reaches responding/responded/acknowledged. CPA-class roles only on cookie sessions; Bearer keys gate via `notices.write`.
notices.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | SIDES exchange / claim UUID |
Request body SidesSubmitBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
response | object | required | — |
Responses
- 200Submitted
SidesSubmitResponseField Type Required Description okenum: truerequired — statusenum: "responded"required — response_filestringrequired — - 400Validation error / unsupported exchange type
SidesValidationErrorResponse - 401Unauthorized
SidesUnauthorizedResponse - 403Forbidden — CPA access required
SidesUnauthorizedResponse - 404Exchange not found
SidesNotFoundResponse - 409Exchange already submitted/acknowledged — re-submit blocked
SidesValidationErrorResponse - 422Zod validation failed (with broker-rule remediation)
SidesValidationErrorResponse - 429Rate limit exceeded
SidesRateLimitResponse - 500Server error (e.g., missing SSN in raw_request_xml)
SidesUnauthorizedResponse - 502Broker rejected (with business-rule errors)
SidesValidationErrorResponse
GET/api/sides/transmissionsList SIDES transmissions
SIDES transmission audit log. Filter by direction (inbound/outbound) and transmission_status. CPA-class roles only on cookie sessions; Bearer keys gate via `audit.read`.
audit.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
direction | query | enum: "inbound" | "outbound" | optional | — |
status | query | string | optional | — |
limit | query | integer | optional | — |
offset | query | integer | optional | — |
Responses
- 200Transmissions
SidesTransmissionsListResponseField Type Required Description transmissionsarray<SidesTransmission>required — totalintegerrequired — - 401Unauthorized
SidesUnauthorizedResponse - 403Forbidden — CPA access required
SidesUnauthorizedResponse - 429Rate limit exceeded
SidesRateLimitResponse - 500Server error
SidesUnauthorizedResponse
GET/api/sides/claimsList SIDES claims (legacy)
List SIDES claims (legacy /sides_separation_requests path). Filter by pending / auto_filled / in_review / overdue / submitted. CPA-class roles only on cookie sessions; Bearer keys gate via `notices.read`.
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
filter | query | enum: "all" | "pending" | "auto_filled" | "in_review" | … | optional | — |
limit | query | integer | optional | — |
offset | query | integer | optional | — |
Responses
- 200Claims
SidesClaimsListResponseField Type Required Description claimsarray<SidesClaimListItem>required — totalintegerrequired — - 401Unauthorized
SidesUnauthorizedResponse - 403Forbidden — CPA access required
SidesUnauthorizedResponse - 429Rate limit exceeded
SidesRateLimitResponse - 500Server error
SidesUnauthorizedResponse
GET/api/sides/claims/{id}Get SIDES claim (legacy)
SIDES claim detail (legacy path) with related transmissions + linked notice. CPA-class roles only on cookie sessions; Bearer keys gate via `notices.read`.
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | SIDES exchange / claim UUID |
Responses
- 200Claim + transmissions + notice
SidesClaimDetailResponseField Type Required Description claimobjectrequired — transmissionsarray<SidesTransmission>required — noticeobjectrequired — - 401Unauthorized
SidesUnauthorizedResponse - 403Forbidden — CPA access required
SidesUnauthorizedResponse - 404Claim not found
SidesNotFoundResponse - 429Rate limit exceeded
SidesRateLimitResponse - 500Server error
SidesUnauthorizedResponse
POST/api/sides/claims/{id}/respondSave SIDES claim draft (legacy)
Save a draft response on the legacy claims path. The `approve` action is permanently blocked (410) — the legacy table lacks the FEIN/state-account/SSN data required for a valid SIDES response. Use the v2 sides_exchanges path instead. CPA-class roles only on cookie sessions; Bearer keys gate via `notices.write`. Cookie sessions go through the Stripe subscription gate.
notices.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | SIDES exchange / claim UUID |
Request body SidesClaimRespondBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
action | enum: "save" | "approve" | required | — |
separation_reason | string | optional | — |
last_day_worked | string | optional | — |
final_wages_cents | integer | optional | — |
discharge_reason | string | optional | — |
voluntary_quit_reason | string | optional | — |
return_to_work_offered | boolean | optional | — |
notes | string | optional | — |
Responses
- 200Draft saved
SidesClaimRespondResponseField Type Required Description successenum: truerequired — response_statusstringrequired — actionstringrequired — - 400Validation error
SidesValidationErrorResponse - 401Unauthorized
SidesUnauthorizedResponse - 402Subscription required (cookie-session callers only)
SidesUnauthorizedResponse - 403Forbidden — CPA access required
SidesUnauthorizedResponse - 404Claim not found
SidesNotFoundResponse - 410Approve is permanently blocked on the legacy path
SidesValidationErrorResponse - 429Rate limit exceeded
SidesRateLimitResponse - 500Server error
SidesUnauthorizedResponse
States6
GET/api/statesList state agencies
List state agencies with tax rules for a given year (default 2026). Read-only Kreto reference data — no tenant scope.
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
year | query | integer | optional | — |
Responses
- 200States
StatesListResponseField Type Required Description dataarray<StateAgency>required — countintegerrequired — - 401Unauthorized
MiscUnauthorizedResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
GET/api/states/{code}Get state detail
Single state detail with tax rules, surcharges, notice types, protest rules, POA rules, and statutes. Read-only reference data.
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
code | path | string | required | 2-letter state code |
year | query | integer | optional | — |
Responses
- 200State detail
StateDetailResponseField Type Required Description dataStateDetailrequired — - 401Unauthorized
MiscUnauthorizedResponse - 404State not found
MiscNotFoundResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
GET/api/states/{code}/noticesList state notice types
List state notice types ranked by financial impact. Read-only reference data.
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
code | path | string | required | 2-letter state code |
Responses
- 200Notice types
StateNoticeTypesResponseField Type Required Description state_codestringrequired — state_namestringrequired — dataarray<StateNoticeType>required — countintegerrequired — - 401Unauthorized
MiscUnauthorizedResponse - 404State not found
MiscNotFoundResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
GET/api/states/{code}/poaList state POA rules
List POA rules for a state. Read-only reference data.
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
code | path | string | required | 2-letter state code |
Responses
- 200POA rules
StatePoaResponseField Type Required Description state_codestringrequired — state_namestringrequired — dataarray<StatePoaRule>required — countintegerrequired — - 401Unauthorized
MiscUnauthorizedResponse - 404State not found
MiscNotFoundResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
GET/api/states/compareCompare states
Compare up to 5 states side-by-side (full ruleset for each). Read-only reference data.
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
states | query | string | required | — |
year | query | integer | optional | — |
Responses
- 200Comparison data
StatesListResponseField Type Required Description dataarray<StateAgency>required — countintegerrequired — - 400Validation error
MiscValidationErrorResponse - 401Unauthorized
MiscUnauthorizedResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
GET/api/states/withholdingWithholding reciprocity
Withholding reciprocity calculator. Without query params, returns the full reciprocity map. With work_state + home_state, returns the specific reciprocity decision plus each state's full reciprocity list.
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
work_state | query | string | optional | — |
home_state | query | string | optional | — |
Responses
- 200Reciprocity data
StateWithholdingResponseField Type Required Description reciprocityAgreementsobjectoptional — totalStatesWithReciprocityintegeroptional — resultobjectoptional — workStateReciprocityarray<string>optional — homeStateReciprocityarray<string>optional — - 400Validation error
MiscValidationErrorResponse - 401Unauthorized
MiscUnauthorizedResponse - 429Rate limit exceeded
MiscRateLimitResponse
TaxDocuments8
GET/api/tax-documentsList tax document requests
List tax document requests for caller's tenant. Bearer keys gate via `notices.read`.
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
entity_id | query | string · uuid | optional | — |
status | query | string | optional | — |
tax_year | query | integer | optional | — |
Responses
- 200Requests
TaxDocumentRequestsListResponseField Type Required Description successenum: truerequired — requestsarray<TaxDocumentRequest>required — countintegerrequired — - 400Validation error
MiscValidationErrorResponse - 401Unauthorized
MiscUnauthorizedResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
POST/api/tax-documentsCreate tax document request
Create a tax document collection request with optional AI checklist generation (KRT-322). Cookie sessions go through rate-limit + idempotency middleware. CPA-class roles only on cookie sessions; Bearer keys gate via `notices.write`.
notices.writeRequest body TaxDocumentRequestCreateBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
entity_id | string · uuid | required | — |
client_id | string · uuid | optional | — |
tax_year | integer | required | — |
tax_type | enum: "personal" | "business" | required | — |
entity_type | enum: "individual" | "s_corp" | "c_corp" | "partnership" | … | optional | — |
notice_id | string · uuid | optional | — |
due_date | string | optional | — |
generate_checklist | boolean | optional | — |
prior_year_items | array<string> | optional | — |
Responses
- 201Request created
TaxDocumentRequestCreateResponseField Type Required Description successenum: truerequired — requestTaxDocumentRequestrequired — items_countintegerrequired — - 400Validation error
MiscValidationErrorResponse - 401Unauthorized
MiscUnauthorizedResponse - 403Forbidden — CPA access required
MiscUnauthorizedResponse - 404Entity not found in caller's tenant
MiscNotFoundResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
GET/api/tax-documents/{id}Get tax document request
Get tax document request detail with all items.
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Tax document request UUID |
Responses
- 200Request + items
TaxDocumentRequestDetailResponseField Type Required Description successenum: truerequired — requestTaxDocumentRequestrequired — itemsarray<TaxDocumentRequestItem>required — - 400Validation error
MiscValidationErrorResponse - 401Unauthorized
MiscUnauthorizedResponse - 404Request not found
MiscNotFoundResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
PATCH/api/tax-documents/{id}/items/{itemId}Update tax document item
Update a tax document request item. CPA-class can update label / description / required; client_user / client can update status / uploaded_file / notes. Auto-completes the parent request when all required items reach verified or waived. Bearer keys gate via `notices.write` (treated as CPA-class).
notices.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Tax document request UUID |
itemId | path | string · uuid | required | Tax document item UUID |
Request body TaxDocumentItemUpdateBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
status | enum: "pending" | "uploaded" | "verified" | "rejected" | … | optional | — |
uploaded_file | string | optional | — |
notes | string | optional | — |
label | string | optional | — |
description | string | optional | — |
required | boolean | optional | — |
Responses
- 200Item updated
TaxDocumentItemUpdateResponseField Type Required Description successenum: truerequired — itemTaxDocumentRequestItemrequired — - 400Validation error / expired request
MiscValidationErrorResponse - 401Unauthorized
MiscUnauthorizedResponse - 404Request or item not found
MiscNotFoundResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
GET/api/tax-documents/{id}/remindersList tax document reminders
List reminders sent for a tax document request + current reminder settings (paused state, custom deadline, due date). Bearer keys gate via `notices.read`.
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Tax document request UUID |
Responses
- 200Reminders + settings
TaxDocumentRemindersListResponseField Type Required Description successenum: truerequired — remindersarray<TaxDocumentReminder>required — settingsobjectrequired — - 400Validation error
MiscValidationErrorResponse - 401Unauthorized
MiscUnauthorizedResponse - 404Request not found
MiscNotFoundResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
PATCH/api/tax-documents/{id}/remindersUpdate tax document reminder settings
Update reminder settings (pause/resume, set custom deadline). CPA-class roles only on cookie sessions; Bearer keys gate via `notices.write`.
notices.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Tax document request UUID |
Request body TaxDocumentRemindersUpdateBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
reminders_paused | boolean | optional | — |
custom_deadline | string | optional | — |
Responses
- 200Settings updated
TaxDocumentRemindersUpdateResponseField Type Required Description successenum: truerequired — - 400Validation error
MiscValidationErrorResponse - 401Unauthorized
MiscUnauthorizedResponse - 403Forbidden — CPA access required
MiscUnauthorizedResponse - 404Request not found
MiscNotFoundResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
POST/api/tax-documents/{id}/reminders/sendSend manual reminder
Send a manual reminder for a specific tax document request (KRT-324). CPA-class roles only on cookie sessions; Bearer keys gate via `notices.write`. Refused for completed/expired requests.
notices.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Tax document request UUID |
Responses
- 200Reminder sent (or skipped with reason)
TaxDocumentManualReminderResponseField Type Required Description successbooleanoptional — reminder_idstring · uuidrequired — pending_items_countintegerrequired — skippedbooleanoptional — skip_reasonstringoptional — - 400Validation error
MiscValidationErrorResponse - 401Unauthorized
MiscUnauthorizedResponse - 403Forbidden — CPA access required
MiscUnauthorizedResponse - 404Request not found
MiscNotFoundResponse - 422Cannot send reminder for completed/expired request
MiscValidationErrorResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
POST/api/tax-documents/reminders/bulkBulk-send tax document reminders
Send reminders for the SELECTED documents. Each document id is resolved to its request_id (tenant-scoped) and each distinct request is reminded and audited independently (one audit row per request). Terminal (complete/expired) requests are skipped. CPA-class roles only on cookie sessions; Bearer keys gate via `notices.write`.
notices.writeRequest body TaxDocumentBulkRemindersRequest
| Field | Type | Required | Description |
|---|---|---|---|
ids | array<string · uuid> | required | Selected document ids (1..200) |
Responses
- 200Bulk send result (applied / skipped / failed)
TaxDocumentBulkRemindersResponseField Type Required Description appliedintegerrequired — skippedarray<object>required — failedarray<object>required — - 401Unauthorized
MiscUnauthorizedResponse - 403Forbidden — CPA access required
MiscUnauthorizedResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
TaxLiens2
GET/api/tax-liensList tax liens
List tax liens for the caller's tenant. Filters: entity_id, status, lien_type. Bearer keys gate via `notices.read`.
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
entity_id | query | string · uuid | optional | — |
status | query | string | optional | — |
lien_type | query | string | optional | — |
limit | query | integer | optional | — |
offset | query | integer | optional | — |
Responses
- 200Tax liens
TaxLiensListResponseField Type Required Description liensarray<TaxLien>required — totalintegerrequired — - 401Unauthorized
MiscUnauthorizedResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
POST/api/tax-liensCreate tax lien
Create a tax lien record. Bearer keys gate via `notices.write`.
notices.writeRequest body TaxLienCreateBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
entity_id | string · uuid | required | — |
lien_amount | number | required | — |
notice_id | string · uuid | optional | — |
lien_type | string | optional | — |
lien_number | string | optional | — |
filing_date | string | optional | — |
filing_jurisdiction | string | optional | — |
tax_periods | array<string> | optional | — |
tax_type | string | optional | — |
response_deadline | string | optional | — |
release_conditions | string | optional | — |
agency | string | optional | — |
Responses
- 201Tax lien created
TaxLienCreateResponseField Type Required Description lienTaxLienrequired — - 400Validation error
MiscValidationErrorResponse - 401Unauthorized
MiscUnauthorizedResponse - 404Entity not found in caller's tenant
MiscNotFoundResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
WageHour2
GET/api/wage-hourList W&H investigations
List Wage & Hour investigations (compliance category #5 — DOL). Bearer keys gate via `notices.read`.
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
entity_id | query | string · uuid | optional | — |
status | query | string | optional | — |
investigation_type | query | string | optional | — |
limit | query | integer | optional | — |
offset | query | integer | optional | — |
Responses
- 200Investigations
WageHourListResponseField Type Required Description investigationsarray<WageHourInvestigation>required — totalintegerrequired — - 401Unauthorized
MiscUnauthorizedResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
POST/api/wage-hourCreate W&H investigation
Create a Wage & Hour investigation record. Bearer keys gate via `notices.write`.
notices.writeRequest body WageHourCreateBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
entity_id | string · uuid | required | — |
investigation_type | string | required | — |
notice_id | string · uuid | optional | — |
investigation_number | string | optional | — |
complaint_type | string | optional | — |
investigation_scope | string | optional | — |
back_wages_owed | number | optional | — |
penalty_amount | number | optional | — |
workers_affected | integer | optional | — |
classification_issue | string | optional | — |
misclassified_count | integer | optional | — |
overtime_hours_owed | number | optional | — |
overtime_rate | number | optional | — |
notice_date | string | optional | — |
response_deadline | string | optional | — |
hearing_date | string | optional | — |
investigator_name | string | optional | — |
agency | string | optional | — |
Responses
- 201Investigation created
WageHourCreateResponseField Type Required Description investigationWageHourInvestigationrequired — - 400Validation error
MiscValidationErrorResponse - 401Unauthorized
MiscUnauthorizedResponse - 404Entity not found in caller's tenant
MiscNotFoundResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
WorkersComp6
GET/api/workers-compList W/C policies
List workers' comp policies for the caller's tenant (compliance category #3). Bearer keys gate via `notices.read`.
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
entity_id | query | string · uuid | optional | — |
status | query | string | optional | — |
limit | query | integer | optional | — |
offset | query | integer | optional | — |
Responses
- 200Policies
WorkersCompPoliciesListResponseField Type Required Description policiesarray<WorkersCompPolicy>required — totalintegerrequired — - 401Unauthorized
MiscUnauthorizedResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
POST/api/workers-compCreate W/C policy
Create a workers' comp policy. Bearer keys gate via `notices.write`.
notices.writeRequest body WorkersCompPolicyCreateBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
entity_id | string · uuid | required | — |
policy_number | string | required | — |
carrier | string | required | — |
state | string | required | — |
e_mod | number | optional | — |
annual_premium | number | optional | — |
status | string | optional | — |
effective_date | string | optional | — |
expiration_date | string | optional | — |
Responses
- 201Policy created
WorkersCompPolicyCreateResponseField Type Required Description policyWorkersCompPolicyrequired — - 400Validation error
MiscValidationErrorResponse - 401Unauthorized
MiscUnauthorizedResponse - 404Entity not found in caller's tenant
MiscNotFoundResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
GET/api/workers-comp/auditsList W/C audits
List workers' comp audits for the caller's tenant. Each row carries an inlined dispute recommendation when both original_premium and audited_premium are present. Bearer keys gate via `notices.read`.
notices.readParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
entity_id | query | string · uuid | optional | — |
status | query | string | optional | — |
limit | query | integer | optional | — |
offset | query | integer | optional | — |
Responses
- 200Audits
WorkersCompAuditsListResponseField Type Required Description auditsarray<WorkersCompAudit>required — totalintegerrequired — - 401Unauthorized
MiscUnauthorizedResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
POST/api/workers-comp/auditsCreate W/C audit
Create a workers' comp audit record. Bearer keys gate via `notices.write`. Cookie sessions go through the Stripe subscription gate; Bearer keys bypass.
notices.writeRequest body WorkersCompAuditCreateBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
entity_id | string · uuid | required | — |
policy_id | string · uuid | optional | — |
notice_id | string · uuid | optional | — |
audit_type | string | optional | — |
period_start | string | optional | — |
period_end | string | optional | — |
original_premium | number | optional | — |
audited_premium | number | optional | — |
deadline | string | optional | — |
Responses
- 201Audit created
WorkersCompAuditCreateResponseField Type Required Description auditWorkersCompAuditrequired — - 400Validation error
MiscValidationErrorResponse - 401Unauthorized
MiscUnauthorizedResponse - 402Subscription required (cookie-session callers only)
MiscUnauthorizedResponse - 404Entity not found in caller's tenant
MiscNotFoundResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
POST/api/workers-comp/calculate-emodCalculate W/C e-mod
Stateless e-mod (experience modifier) calculator for workers' comp. No tenant data is read or written. Bearer keys gate via `notices.read`.
notices.readRequest body WorkersCompEmodBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
actualLosses | number | required | — |
expectedLosses | number | required | — |
credibilityWeight | number | optional | — |
ballastValue | number | optional | — |
Responses
- 200e-mod calculation
WorkersCompEmodResponseField Type Required Description eModnumberrequired — discountnumberoptional — surchargenumberoptional — - 400Validation error
MiscValidationErrorResponse - 401Unauthorized
MiscUnauthorizedResponse - 429Rate limit exceeded
MiscRateLimitResponse
Workflows4
GET/api/workflowsList workflow rules
List workflow rules for the caller's tenant.
notices.readResponses
- 200Rules
WorkflowRulesListResponseField Type Required Description rulesarray<WorkflowRule>required — - 401Unauthorized
MiscUnauthorizedResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
POST/api/workflowsCreate workflow rule
Create a workflow rule. Trigger must be one of `notice.created`, `notice.deadline_approaching`, `notice.status_changed`, or `document.uploaded`.
notices.writeRequest body WorkflowRuleCreateBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
name | string | required | — |
trigger | enum: "notice.created" | "notice.deadline_approaching" | "notice.status_changed" | "document.uploaded" | required | — |
conditions | array<WorkflowCondition> | optional | — |
actions | array<WorkflowAction> | optional | — |
Responses
- 201Rule created
WorkflowRuleResponseField Type Required Description ruleWorkflowRulerequired — - 400Validation error
MiscValidationErrorResponse - 401Unauthorized
MiscUnauthorizedResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
PATCH/api/workflows/{id}Update workflow rule
Update a workflow rule (toggle is_active, edit fields).
notices.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Workflow rule UUID |
Request body WorkflowRuleUpdateBodyrequired
| Field | Type | Required | Description |
|---|---|---|---|
name | string | optional | — |
trigger | enum: "notice.created" | "notice.deadline_approaching" | "notice.status_changed" | "document.uploaded" | optional | — |
conditions | array<WorkflowCondition> | optional | — |
actions | array<WorkflowAction> | optional | — |
is_active | boolean | optional | — |
Responses
- 200Rule updated
WorkflowRuleResponseField Type Required Description ruleWorkflowRulerequired — - 400Validation error
MiscValidationErrorResponse - 401Unauthorized
MiscUnauthorizedResponse - 404Rule not found
MiscNotFoundResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse
DELETE/api/workflows/{id}Delete workflow rule
Delete a workflow rule.
notices.writeParameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string · uuid | required | Workflow rule UUID |
Responses
- 200Rule deleted
objectField Type Required Description successenum: truerequired — - 400Validation error
MiscValidationErrorResponse - 401Unauthorized
MiscUnauthorizedResponse - 404Rule not found
MiscNotFoundResponse - 429Rate limit exceeded
MiscRateLimitResponse - 500Server error
MiscUnauthorizedResponse