Support/Builder Guide/Headless application guide and copy/paste kit

Builder Guide

Headless application guide and copy/paste kit

Build a custom frontend over BuildWithHQ authentication, scoped APIs, first-class modules, Inbox, Workflow, Files and exact server-side authorization.

Capabilities
23
Page routes
166
Additional routes
47

A headless BuildWithHQ application replaces the native page presentation with your own React, Vue, mobile, desktop, or server-rendered interface. It does not replace authentication, tenant routing, DataRoles, Locations, stored-procedure contracts, audit, rate limits, files, Workflow, Inbox, or AI authorization.

Note

This guide is generated from the same catalog as the native React kit: 23 capabilities, 166 page-module routes, and 47 additional tenant/Design routes. It does not invent a second backend.

1. Choose the correct headless boundary

CallerUseDo not do
Custom tenant browser UIThe current same-origin tenant session plus the typed tenant APIs cataloged below.Do not store the access token in localStorage or submit tenant/database identity as authorization.
External server or integrationThe published Developer Platform, app-bound credentials, generated OpenAPI and versioned gateway routes.Do not place server API keys in browser/mobile bundles or call internal tenant routes as an unauthenticated proxy.
Custom appliance serviceA declared installed-service endpoint with reviewed egress, secret references, action permissions and correlation.Do not expose provider credentials, unrestricted SQL or tenant infrastructure to the frontend.
Important

The generated transport below intentionally accepts only same-origin /api/ paths. If the frontend runs on another origin, use the published Developer API contract and its supported authentication/CORS boundary; do not weaken this check.

2. Copy the same-origin transport

The transport adds the current in-memory bearer token, delegates unsafe-method CSRF handling to the existing security helper, assigns a correlation ID, preserves server-side status/code/error/correlation details, clears local session state on 401, and never accepts a database name.


export type HeadlessMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";

export interface HeadlessRequest {
  readonly method?: HeadlessMethod;
  readonly body?: unknown;
  readonly signal?: AbortSignal;
  readonly headers?: Readonly<Record<string, string>>;
}

export interface HeadlessTransportOptions {
  readonly accessToken: () => string | null | undefined;
  readonly fetchImplementation?: typeof fetch;
  readonly applyCsrfHeader?: (headers: Headers, method: string) => void;
  readonly onUnauthorized?: () => void;
}

export interface HeadlessTransport {
  request<T>(path: string, request?: HeadlessRequest): Promise<T>;
}

export class HeadlessApiError extends Error {
  public constructor(
    message: string,
    public readonly status: number,
    public readonly code: string,
    public readonly correlationId?: string,
    public readonly retryAfterSeconds?: number,
  ) { super(message); this.name = "HeadlessApiError"; }
}

const sameOriginApiPath = (path: string): string => {
  if (!path.startsWith("/api/") || path.includes("://") || path.includes("#") || path.length > 4000) {
    throw new TypeError("Headless tenant requests require a bounded same-origin /api/ path.");
  }
  return path;
};

const readProblem = async (response: Response): Promise<HeadlessApiError> => {
  let body: Record<string, unknown> = {};
  try { body = await response.json() as Record<string, unknown>; } catch { /* safe fallback below */ }
  const retryHeader = Number(response.headers.get("Retry-After"));
  const retryBody = Number(body.retryAfterSeconds);
  const retryAfterSeconds = Number.isFinite(retryBody) ? retryBody : Number.isFinite(retryHeader) ? retryHeader : undefined;
  return new HeadlessApiError(
    typeof body.error === "string" ? body.error : `Request failed (${response.status}).`,
    response.status,
    typeof body.code === "string" ? body.code : "request_failed",
    typeof body.correlationId === "string" ? body.correlationId : response.headers.get("X-Correlation-ID") ?? undefined,
    retryAfterSeconds,
  );
};

export const createSameOriginHeadlessTransport = (options: HeadlessTransportOptions): HeadlessTransport => {
  const fetchImplementation = options.fetchImplementation ?? globalThis.fetch;
  if (!fetchImplementation) throw new TypeError("A fetch implementation is required.");
  return {
    async request<T>(path: string, request: HeadlessRequest = {}): Promise<T> {
      const method = request.method ?? "GET";
      const headers = new Headers({ Accept: "application/json", ...request.headers });
      const token = options.accessToken();
      if (!token) { options.onUnauthorized?.(); throw new HeadlessApiError("Sign in before loading tenant data.", 401, "tenant_session_required"); }
      headers.set("Authorization", `Bearer ${token}`);
      headers.set("X-Correlation-ID", crypto.randomUUID());
      if (request.body !== undefined) headers.set("Content-Type", "application/json");
      options.applyCsrfHeader?.(headers, method);
      const response = await fetchImplementation(sameOriginApiPath(path), {
        method,
        credentials: "same-origin",
        headers,
        body: request.body === undefined ? undefined : JSON.stringify(request.body),
        signal: request.signal,
      });
      if (response.status === 401) options.onUnauthorized?.();
      if (!response.ok) throw await readProblem(response);
      if (response.status === 204) return undefined as T;
      return await response.json() as T;
    },
  };
};

/* In apps/tenant-runtime, inject getTenantAccessToken, applyCsrfHeader and
   clearTenantSession. Keep refresh/session rotation in the official auth client. */

Wire it to the official tenant session

import { clearTenantSession, getTenantAccessToken } from "./api";
import { applyCsrfHeader } from "./webSecurity";
import { createSameOriginHeadlessTransport } from "./HeadlessTransport";

export const transport = createSameOriginHeadlessTransport({
  accessToken: getTenantAccessToken,
  applyCsrfHeader,
  onUnauthorized: clearTenantSession,
});

// Keep login, refresh rotation, logout and session restore in the official
// tenant auth client. The custom component consumes only this transport.

Let the existing login/refresh client own refresh-cookie rotation and session restore. A 401 should return the app to its sign-in state; a 403 is an authorization denial, 404 keeps absent and foreign identifiers indistinguishable, 409 requires reloading stale state, and 429 requires honoring the retry window.

3. Working, paginated read/write example

This example requests exactly one 25-row page from /api/modules/contacts, parses the response through parseContactList, creates through the reviewed POST contract, validates the receipt with parseContactMutation, aborts obsolete reads, and never fetches a full table to filter in React.


import { useEffect, useState, type FormEvent } from "react";
import {
  contactsModule,
  parseContactList,
  parseContactMutation,
  type ContactList,
} from "@buildwithhq/module-sdk";
import type { HeadlessTransport } from "./HeadlessTransport";

export interface HeadlessContactsExampleProps {
  readonly transport: HeadlessTransport;
  readonly styled?: boolean;
}

export const HeadlessContactsExample = ({ transport, styled = false }: HeadlessContactsExampleProps) => {
  const [page, setPage] = useState(1);
  const [search, setSearch] = useState("");
  const [result, setResult] = useState<ContactList>();
  const [error, setError] = useState<string>();
  const [refresh, setRefresh] = useState(0);
  const [firstName, setFirstName] = useState("");
  const [lastName, setLastName] = useState("");
  const [email, setEmail] = useState("");

  useEffect(() => {
    const controller = new AbortController();
    const query = new URLSearchParams({ pageNumber: String(page), pageSize: "25" });
    if (search.trim()) query.set("search", search.trim());
    setError(undefined);
    void transport.request<unknown>(`${contactsModule.apiBasePath}?${query}`, { signal: controller.signal })
      .then((value) => setResult(parseContactList(value)))
      .catch((failure: unknown) => { if (!controller.signal.aborted) setError(failure instanceof Error ? failure.message : "Contacts unavailable."); });
    return () => controller.abort();
  }, [page, refresh, search, transport]);

  const create = async (event: FormEvent) => {
    event.preventDefault(); setError(undefined);
    try {
      const value = await transport.request<unknown>(contactsModule.apiBasePath, {
        method: "POST", body: { firstName, lastName, email },
      });
      parseContactMutation(value);
      setFirstName(""); setLastName(""); setEmail(""); setPage(1); setRefresh((value) => value + 1);
    } catch (failure) { setError(failure instanceof Error ? failure.message : "Contact could not be created."); }
  };

  return <section className={styled ? "bwhq-headless-resource" : undefined}>
    <header><div><p>Headless first-class module</p><h2>Contacts</h2></div><label>Search visible contacts<input type="search" value={search} onChange={(event) => { setSearch(event.target.value); setPage(1); }} /></label></header>
    {error && <p role="alert">{error}</p>}
    {!result && !error && <p role="status">Loading contacts…</p>}
    {result && <><ul>{result.items.map((contact) => <li key={contact.recordId}><strong>{contact.title}</strong><span>{contact.email || contact.companyName || "No secondary value"}</span></li>)}</ul><nav aria-label="Contact pages"><button disabled={page <= 1} onClick={() => setPage((value) => value - 1)} type="button">Previous</button><span>Page {result.pageNumber} of {Math.max(1, result.totalPages)}</span><button disabled={page >= result.totalPages} onClick={() => setPage((value) => value + 1)} type="button">Next</button></nav></>}
    <form onSubmit={(event) => void create(event)}><h3>Create a contact</h3><label>First name<input value={firstName} onChange={(event) => setFirstName(event.target.value)} /></label><label>Last name<input value={lastName} onChange={(event) => setLastName(event.target.value)} /></label><label>Email<input type="email" value={email} onChange={(event) => setEmail(event.target.value)} /></label><button type="submit">Create contact</button></form>
  </section>;
};

Use it

import { HeadlessContactsExample } from "./HeadlessContactsExample";
import { transport } from "./transport";

export const ContactsPage = () => (
  <HeadlessContactsExample transport={transport} styled />
);
Tip

Copy the pattern, not the Contacts field names: bounded query parameters, unknown JSON at the transport boundary, official SDK parser, server pagination, explicit loading/empty/error states, and one narrow mutation receipt.

4. Headless data bindings

For custom page-shaped projections, request a reviewed binding key. The server resolves it to an approved sp_ds_* contract and applies the signed-in identity. The client does not send SQL, a procedure name, a SaaS ID, or a database selector.

import { parseRuntimeDataBinding } from "@buildwithhq/page-runtime";
import { transport } from "./transport";

export const loadOpenWork = async (signal: AbortSignal) => {
  const bindingKey = "work.open";
  const raw = await transport.request<unknown>(
    `/api/runtime/data/${encodeURIComponent(bindingKey)}`,
    { signal },
  );
  return parseRuntimeDataBinding(raw, bindingKey).data;
};

5. Universal Inbox, support tickets and GoClaw

The official package exposes typed clients independently from its native UI. A headless component can consume those clients for bounded queues, ticket-only views, badge/notifications, email ticketing settings, human state, Workflow decisions and GoClaw review work. Use the native components when you want the complete lifecycle without reimplementing every control.

import {
  createApprovalQueueHttpClient,
  createUniversalInboxHttpClient,
} from "@buildwithhq/universal-inbox";
import { ensureCsrfToken } from "./webSecurity";
import { getTenantAccessToken } from "./api";
import {
  HeadlessApprovalQueueStarter,
  HeadlessInboxQueueStarter,
} from "./UniversalInboxStarters";

const inboxClient = createUniversalInboxHttpClient({
  accessToken: getTenantAccessToken,
  csrfToken: ensureCsrfToken,
});
const approvalClient = createApprovalQueueHttpClient({
  accessToken: getTenantAccessToken,
  csrfToken: ensureCsrfToken,
});

export const SupportQueue = () => (
  <HeadlessInboxQueueStarter client={inboxClient} ticketingOnly styled />
);
export const AiReviewQueue = () => (
  <HeadlessApprovalQueueStarter client={approvalClient} styled />
);
Copy all native and headless Inbox/GoClaw starters

import { useEffect, useState } from "react";
import {
  GoClawApprovalQueue,
  UniversalInbox,
  type ApprovalQueueClient,
  type ApprovalQueueItem,
  type InboxQueueItem,
  type UniversalInboxClient,
} from "@buildwithhq/universal-inbox";

interface InboxStarterProps {
  readonly client: UniversalInboxClient;
  readonly ticketingOnly?: boolean;
  readonly assignedToMe?: boolean;
  readonly onOpen?: (inboxItemId: string) => void;
  readonly styled?: boolean;
}

export const HeadlessInboxQueueStarter = ({ client, ticketingOnly, assignedToMe, onOpen, styled = false }: InboxStarterProps) => {
  const [items, setItems] = useState<readonly InboxQueueItem[]>([]);
  const [error, setError] = useState<string>();
  const [loading, setLoading] = useState(true);
  useEffect(() => {
    const controller = new AbortController();
    setLoading(true); setError(undefined);
    void client.list({ ticketingOnly, assignedToMe, topN: 100 }, controller.signal)
      .then(setItems)
      .catch((failure: unknown) => { if (!controller.signal.aborted) setError(failure instanceof Error ? failure.message : "Inbox unavailable."); })
      .finally(() => { if (!controller.signal.aborted) setLoading(false); });
    return () => controller.abort();
  }, [assignedToMe, client, ticketingOnly]);
  return <section aria-busy={loading} className={styled ? "bwhq-headless-list" : undefined}>
    <h2>{ticketingOnly ? "Support tickets" : "Universal Inbox"}</h2>
    {loading && <p role="status">Loading inbox…</p>}
    {error && <p role="alert">{error}</p>}
    {!loading && !error && items.length === 0 && <p>No visible work.</p>}
    <ul>{items.map((item) => <li key={item.inboxItemId}><button type="button" onClick={() => onOpen?.(item.inboxItemId)}><strong>{item.ticket?.key ? item.ticket.key + " · " : ""}{item.subject || item.source.sourceType}</strong><span>{item.status} · {item.previewText || "No preview"}</span></button></li>)}</ul>
  </section>;
};

interface ApprovalStarterProps {
  readonly client: ApprovalQueueClient;
  readonly onOpen?: (item: ApprovalQueueItem) => void;
  readonly styled?: boolean;
}

export const HeadlessApprovalQueueStarter = ({ client, onOpen, styled = false }: ApprovalStarterProps) => {
  const [items, setItems] = useState<readonly ApprovalQueueItem[]>([]);
  const [error, setError] = useState<string>();
  useEffect(() => {
    const controller = new AbortController();
    void client.list(100, controller.signal).then(setItems)
      .catch((failure: unknown) => { if (!controller.signal.aborted) setError(failure instanceof Error ? failure.message : "Approval queue unavailable."); });
    return () => controller.abort();
  }, [client]);
  return <section className={styled ? "bwhq-headless-list" : undefined}>
    <h2>GoClaw approval work</h2>{error && <p role="alert">{error}</p>}
    <ul>{items.map((item) => <li key={item.suggestionBatchId}><button type="button" onClick={() => onOpen?.(item)}><strong>{item.subject || item.summary || item.sourceType}</strong><span>{item.batchStatus}{item.isStale ? " · stale" : ""}</span></button></li>)}</ul>
  </section>;
};

/* These two exports preserve the complete native behaviors. The bare export adds
   no wrapper CSS, but the native package intentionally ships its own module CSS. */
export const BareNativeUniversalInbox = (props: { readonly client: UniversalInboxClient; readonly initialInboxItemId?: string }) =>
  <UniversalInbox {...props} />;
export const FramedNativeUniversalInbox = (props: { readonly client: UniversalInboxClient; readonly initialInboxItemId?: string }) =>
  <div className="bwhq-native-frame"><UniversalInbox {...props} /></div>;
export const BareNativeGoClawApprovalQueue = (props: { readonly client: ApprovalQueueClient }) =>
  <GoClawApprovalQueue {...props} />;
export const FramedNativeGoClawApprovalQueue = (props: { readonly client: ApprovalQueueClient }) =>
  <div className="bwhq-native-frame"><GoClawApprovalQueue {...props} /></div>;
Important

The headless list starters demonstrate reads and selection. They do not silently implement ticket resolution, proof/file handling, Workflow approval, GoClaw edits or delivery retry. Call the corresponding typed client method only from an explicit UI action and preserve ActivityVersion/stale-state inputs.

6. Menus and the custom workspace shell

Use the server-returned User Type menu as route eligibility, then render it in your design. Menu visibility is not record permission. The current shell starter stays left aligned and expands the center while allowing an optional 280px context panel.

import { BuildWithHQMenu } from "./BuildWithHQMenu";
import { StyledTenantWorkspaceShell } from "./TenantWorkspaceShell";

export const AppShell = ({ menu, pageKey, children }) => (
  <StyledTenantWorkspaceShell
    applicationName="Your SaaS"
    pageTitle="Workspace"
    menu={<BuildWithHQMenu
      items={menu}
      activePageKey={pageKey}
      resolvePageHref={(key) => `/?page=${encodeURIComponent(key)}`}
      styled
    />}
    contextPanel={<p>Page-specific context belongs here.</p>}
  >
    {children}
  </StyledTenantWorkspaceShell>
);
Copy the complete menu component

import type { ReactNode } from "react";

export interface BuildWithHQMenuItem {
  readonly id: string;
  readonly parentId?: string | null;
  readonly label: string;
  readonly iconKey?: string | null;
  readonly targetType: "Page" | "Group" | "Module" | "External";
  readonly pageKey?: string | null;
  readonly url?: string | null;
  readonly sortOrder: number;
}

export interface BuildWithHQMenuProps {
  readonly items: readonly BuildWithHQMenuItem[];
  readonly activePageKey?: string;
  readonly resolvePageHref: (pageKey: string) => string;
  readonly icon?: (iconKey: string) => ReactNode;
  readonly styled?: boolean;
}

const safeExternalUrl = (value: string | null | undefined): string | undefined => {
  if (!value || value.length > 2000) return undefined;
  try {
    const url = new URL(value);
    return url.protocol === "https:" && !url.username && !url.password ? url.toString() : undefined;
  } catch { return undefined; }
};

export const BuildWithHQMenu = ({ items, activePageKey, resolvePageHref, icon, styled = false }: BuildWithHQMenuProps) => {
  const roots = items.filter((item) => !item.parentId).sort((left, right) => left.sortOrder - right.sortOrder);
  const renderItem = (item: BuildWithHQMenuItem): ReactNode => {
    const children = items.filter((candidate) => candidate.parentId === item.id).sort((left, right) => left.sortOrder - right.sortOrder);
    if (item.targetType === "Group") return <li key={item.id}><span>{item.iconKey && icon?.(item.iconKey)}{item.label}</span>{children.length > 0 && <ul>{children.map(renderItem)}</ul>}</li>;
    const href = item.targetType === "Page" && item.pageKey ? resolvePageHref(item.pageKey)
      : item.targetType === "External" ? safeExternalUrl(item.url) : undefined;
    return <li key={item.id}>{href ? <a href={href} aria-current={item.pageKey === activePageKey ? "page" : undefined}>{item.iconKey && icon?.(item.iconKey)}{item.label}</a> : <span aria-disabled="true">{item.label}</span>}</li>;
  };
  return <nav aria-label="Application" className={styled ? "bwhq-app-menu" : undefined}><ul>{roots.map(renderItem)}</ul></nav>;
};
Copy the complete workspace shell

import type { ReactNode } from "react";

export interface TenantWorkspaceShellProps {
  readonly applicationName: string;
  readonly pageTitle: string;
  readonly menu: ReactNode;
  readonly children: ReactNode;
  readonly headerActions?: ReactNode;
  readonly contextPanel?: ReactNode;
  readonly styled?: boolean;
}

const TenantWorkspaceShellBody = ({ applicationName, pageTitle, menu, children, headerActions, contextPanel, styled = false }: TenantWorkspaceShellProps) => (
  <div className={styled ? "bwhq-workspace" : undefined}>
    <header className={styled ? "bwhq-workspace__header" : undefined}>
      <div><p>{applicationName}</p><h1>{pageTitle}</h1></div>
      {headerActions && <div aria-label="Page actions">{headerActions}</div>}
    </header>
    <div className={styled ? "bwhq-workspace__columns" : undefined}>
      <aside aria-label="Application menu" className={styled ? "bwhq-workspace__menu" : undefined}>{menu}</aside>
      <main className={styled ? "bwhq-workspace__main" : undefined}>{children}</main>
      {contextPanel && <aside aria-label="Page context" className={styled ? "bwhq-workspace__context" : undefined}>{contextPanel}</aside>}
    </div>
  </div>
);

export const UnstyledTenantWorkspaceShell = (props: Omit<TenantWorkspaceShellProps, "styled">) =>
  <TenantWorkspaceShellBody {...props} styled={false} />;

export const StyledTenantWorkspaceShell = (props: Omit<TenantWorkspaceShellProps, "styled">) =>
  <TenantWorkspaceShellBody {...props} styled />;

7. Files and binary responses

HeadlessTransport is intentionally JSON-only. For multipart upload and Blob download, reuse the current typed uploadFile, downloadFileContent, uploadTenantAsset, and loadTenantAssetContent functions or implement their exact reviewed contracts. Keep MIME/size validation, CSRF, unauthorized-download denial, malware scanning state, orphan cleanup and native File authorization intact.

8. Every capability and exact operation

Each section lists the current integration kind, page key where one exists, API roots, public package-client methods, exact HTTP routes, current browser function and response parser. A background capability with no interactive route is explicitly left without one rather than given an invented endpoint.

Universal Inbox 10 headless operations

Integration: shell-component · Native key: Not a page block
API roots: /api/inbox, /api/inbox/items
Typed client methods: list, get, badge, notifications, deliveryDebug, retryDelivery, setReadState, setStatus, setPriority, setAssignment, getEmailTicketingSettings, setEmailTicketing, decideWorkflowApproval

Exact HTTP routeCurrent browser functionResponse parser
GET
/api/inbox/items
Use the typed transport/clientUse the returned typed contract
GET
/api/inbox/email-channels/ticketing
Use the typed transport/clientUse the returned typed contract
PUT
/api/inbox/email-channels/{channelConnectionId:guid}/ticketing
Use the typed transport/clientUse the returned typed contract
GET
/api/inbox/items/{inboxItemId:guid}
Use the typed transport/clientUse the returned typed contract
GET
/api/inbox/badge
Use the typed transport/clientUse the returned typed contract
GET
/api/inbox/notifications
Use the typed transport/clientUse the returned typed contract
GET
/api/inbox/delivery/debug
Use the typed transport/clientUse the returned typed contract
POST
/api/inbox/delivery/{outboundMessageId:guid}/retry
Use the typed transport/clientUse the returned typed contract
PUT
/api/inbox/items/{inboxItemId:guid}/human-state
Use the typed transport/clientUse the returned typed contract
POST
/api/inbox/items/{inboxItemId:guid}/workflow-approval
Use the typed transport/clientUse the returned typed contract
Checklists & Signoffs 9 headless operations

Integration: page-module · Native key: module.checklists-signoffs
API roots: /api/modules/checklists-signoffs

Exact HTTP routeCurrent browser functionResponse parser
GET
/api/modules/checklists-signoffs/templates
listChecklistTemplatesparseChecklistTemplateList
POST
/api/modules/checklists-signoffs/templates
createChecklistTemplateparseChecklistMutation
GET
/api/modules/checklists-signoffs/runs
listChecklistRunsparseChecklistRunList
GET
/api/modules/checklists-signoffs/runs/{checklistRunId:guid}
getChecklistRunparseChecklistRunDetail
POST
/api/modules/checklists-signoffs/runs
startChecklistRunparseChecklistMutation
PUT
/api/modules/checklists-signoffs/items/{checklistRunItemId:guid}
updateChecklistItemparseChecklistMutation
POST
/api/modules/checklists-signoffs/items/{checklistRunItemId:guid}/proof
attachChecklistProofparseChecklistMutation
DELETE
/api/modules/checklists-signoffs/proof/{checklistItemEvidenceId:guid}
removeChecklistProofparseChecklistMutation
POST
/api/modules/checklists-signoffs/runs/{checklistRunId:guid}/submit
submitChecklistForSignoffparseChecklistMutation
GoClaw virtual assistant 6 headless operations

Integration: shell-component · Native key: Not a page block
API roots: /api/goclaw/agents, /api/goclaw/approvals
Typed client methods: list, approve, reject, takeOver, retry

Exact HTTP routeCurrent browser functionResponse parser
PUT
/api/goclaw/agents/{goClawAgentId:guid}/authority
Use the typed transport/clientUse the returned typed contract
GET
/api/goclaw/approvals
Use the typed transport/clientUse the returned typed contract
POST
/api/goclaw/approvals/{suggestionBatchId:guid}/approve
Use the typed transport/clientUse the returned typed contract
POST
/api/goclaw/approvals/{suggestionBatchId:guid}/reject
Use the typed transport/clientUse the returned typed contract
POST
/api/goclaw/approvals/{suggestionBatchId:guid}/take-over
Use the typed transport/clientUse the returned typed contract
POST
/api/goclaw/approvals/{suggestionBatchId:guid}/retry
Use the typed transport/clientUse the returned typed contract
AI Insights 0 headless operations

Integration: background-service · Native key: Not a page block
API roots: Background service contracts

This is a scheduled/background capability. Use its governed service and secured feed contracts when exposed; do not invent a browser mutation endpoint.

Contacts 5 headless operations

Integration: page-module · Native key: module.contacts
API roots: /api/modules/contacts

Exact HTTP routeCurrent browser functionResponse parser
GET
/api/modules/contacts
listContactsparseContactList
GET
/api/modules/contacts/{recordId:guid}
getContactparseContactDetail
POST
/api/modules/contacts
createContactparseContactMutation
PUT
/api/modules/contacts/{recordId:guid}
updateContactparseContactMutation
PUT
/api/modules/contacts/{recordId:guid}/favorite
setContactFavoriteparseContactMutation
Work Orders 6 headless operations

Integration: page-module · Native key: module.work-orders
API roots: /api/modules/work-orders

Exact HTTP routeCurrent browser functionResponse parser
GET
/api/modules/work-orders
listWorkOrdersparseWorkOrderList
GET
/api/modules/work-orders/{recordId:guid}
getWorkOrderparseWorkOrderDetail
POST
/api/modules/work-orders
createWorkOrderparseWorkOrderMutation
PUT
/api/modules/work-orders/{recordId:guid}
updateWorkOrderparseWorkOrderMutation
PUT
/api/modules/work-orders/{recordId:guid}/status
setWorkOrderStatusparseWorkOrderMutation
PUT
/api/modules/work-orders/{recordId:guid}/assignment
assignWorkOrderparseWorkOrderMutation
Reservations 7 headless operations

Integration: page-module · Native key: module.reservations
API roots: /api/modules/reservations

Exact HTTP routeCurrent browser functionResponse parser
GET
/api/modules/reservations/products
listReservationProductsparseReservationProductList
POST
/api/modules/reservations/products
saveReservationProductparseReservationMutation
GET
/api/modules/reservations
listReservationsparseReservationList
GET
/api/modules/reservations/{recordId:guid}
getReservationparseReservationDetail
POST
/api/modules/reservations/purchase
purchaseReservationparseReservationMutation
PUT
/api/modules/reservations/{recordId:guid}/status
setReservationStatusparseReservationMutation
PUT
/api/modules/reservations/{recordId:guid}/followups
updateReservationFollowupparseReservationMutation
Calendar 5 headless operations

Integration: page-module · Native key: module.calendar
API roots: /api/modules/calendar

Exact HTTP routeCurrent browser functionResponse parser
GET
/api/modules/calendar
listCalendarEventsparseCalendarEventList
GET
/api/modules/calendar/{recordId:guid}
getCalendarEventparseCalendarEventDetail
POST
/api/modules/calendar
createCalendarEventparseCalendarMutation
PUT
/api/modules/calendar/{recordId:guid}
updateCalendarEventparseCalendarMutation
PUT
/api/modules/calendar/{recordId:guid}/favorite
setCalendarFavoriteparseCalendarMutation
Files & attachments 8 headless operations

Integration: page-module · Native key: module.files
API roots: /api/modules/files

Exact HTTP routeCurrent browser functionResponse parser
GET
/api/modules/files
listFilesparseFileList
GET
/api/modules/files/{recordId:guid}
getFileparseFileDetail
POST
/api/modules/files/upload
uploadFileparseFileMutation
PUT
/api/modules/files/{recordId:guid}
updateFileparseFileMutation
POST
/api/modules/files/{recordId:guid}/attachments
attachFileparseFileMutation
DELETE
/api/modules/files/{recordId:guid}/attachments/{attachmentId:guid}
detachFileparseFileMutation
PUT
/api/modules/files/{recordId:guid}/favorite
setFileFavoriteparseFileMutation
GET
/api/modules/files/{recordId:guid}/content
downloadFileContentUse the returned typed contract
Conversations & messages 7 headless operations

Integration: page-module · Native key: module.conversations
API roots: /api/modules/conversations

Exact HTTP routeCurrent browser functionResponse parser
GET
/api/modules/conversations
listConversationsparseConversationList
GET
/api/modules/conversations/{recordId:guid}
getConversationparseConversationDetail
POST
/api/modules/conversations
createConversationparseConversationMutation
PUT
/api/modules/conversations/{recordId:guid}
updateConversationparseConversationMutation
POST
/api/modules/conversations/{recordId:guid}/messages
postConversationMessageparseConversationMutation
POST
/api/modules/conversations/direct
Use the typed transport/clientUse the returned typed contract
PUT
/api/modules/conversations/{recordId:guid}/favorite
setConversationFavoriteparseConversationMutation
Company news 5 headless operations

Integration: page-module · Native key: module.company-news
API roots: /api/modules/company-news

Exact HTTP routeCurrent browser functionResponse parser
GET
/api/modules/company-news
listCompanyNewsparseCompanyNewsList
GET
/api/modules/company-news/{recordId:guid}
getCompanyNewsparseCompanyNewsDetail
POST
/api/modules/company-news
createCompanyNewsparseCompanyNewsMutation
PUT
/api/modules/company-news/{recordId:guid}
updateCompanyNewsparseCompanyNewsMutation
PUT
/api/modules/company-news/{recordId:guid}/favorite
setCompanyNewsFavoriteparseCompanyNewsMutation
Knowledge Core 37 headless operations

Integration: page-module · Native key: module.knowledge-articles
API roots: /api/modules/knowledge-articles, /api/modules/knowledge-core

Exact HTTP routeCurrent browser functionResponse parser
GET
/api/modules/knowledge-articles
listKnowledgeArticlesparseKnowledgeArticlesList
GET
/api/modules/knowledge-articles/{recordId:guid}
getKnowledgeArticleparseKnowledgeArticleDetail
POST
/api/modules/knowledge-articles
createKnowledgeArticleparseKnowledgeArticleMutation
PUT
/api/modules/knowledge-articles/{recordId:guid}
updateKnowledgeArticleparseKnowledgeArticleMutation
PUT
/api/modules/knowledge-articles/{recordId:guid}/favorite
setKnowledgeArticleFavoriteparseKnowledgeArticleMutation
GET
/api/modules/knowledge-core
listKnowledgeCoreparseKnowledgeCoreList
GET
/api/modules/knowledge-core/{recordId:guid}
getKnowledgeCoreparseKnowledgeCoreDetail
POST
/api/modules/knowledge-core
createKnowledgeCoreparseKnowledgeCoreMutation
PUT
/api/modules/knowledge-core/{recordId:guid}
updateKnowledgeCoreparseKnowledgeCoreMutation
POST
/api/modules/knowledge-core/{recordId:guid}/publish
publishKnowledgeCoreparseKnowledgeCoreMutation
POST
/api/modules/knowledge-core/{recordId:guid}/archive
archiveKnowledgeCoreparseKnowledgeCoreMutation
GET
/api/modules/knowledge-core/{recordId:guid}/revisions
getKnowledgeCoreRevisionsparseKnowledgeRevisions
POST
/api/modules/knowledge-core/{recordId:guid}/restore
Use the typed transport/clientUse the returned typed contract
GET
/api/modules/knowledge-core/collections
listKnowledgeCoreCollectionsparseKnowledgeCollections
POST
/api/modules/knowledge-core/collections
Use the typed transport/clientUse the returned typed contract
PUT
/api/modules/knowledge-core/collections/{collectionId:guid}
Use the typed transport/clientUse the returned typed contract
POST
/api/modules/knowledge-core/collections/{collectionId:guid}/items/{recordId:guid}
Use the typed transport/clientUse the returned typed contract
DELETE
/api/modules/knowledge-core/collections/{collectionId:guid}/items/{recordId:guid}
Use the typed transport/clientUse the returned typed contract
GET
/api/modules/knowledge-core/{recordId:guid}/owners
getKnowledgeCoreOwnersparseKnowledgeOwners
POST
/api/modules/knowledge-core/{recordId:guid}/owners
Use the typed transport/clientUse the returned typed contract
DELETE
/api/modules/knowledge-core/owners/{knowledgeOwnerId:guid}
Use the typed transport/clientUse the returned typed contract
GET
/api/modules/knowledge-core/unowned
Use the typed transport/clientUse the returned typed contract
GET
/api/modules/knowledge-core/reviews
listKnowledgeReviewsparseKnowledgeReviews
POST
/api/modules/knowledge-core/reviews/{reviewCycleId:guid}/begin
beginKnowledgeReviewparseKnowledgeReviewMutation
POST
/api/modules/knowledge-core/reviews/{reviewCycleId:guid}/complete
completeKnowledgeReviewparseKnowledgeReviewMutation
POST
/api/modules/knowledge-core/reviews/{reviewCycleId:guid}/reassign
reassignKnowledgeReviewparseKnowledgeReviewMutation
GET
/api/modules/knowledge-core/health
getKnowledgeHealthparseKnowledgeHealth
GET
/api/modules/knowledge-core/questions
listKnowledgeQuestionsparseKnowledgeQuestions
POST
/api/modules/knowledge-core/questions
createKnowledgeQuestionparseKnowledgeQuestionMutation
POST
/api/modules/knowledge-core/questions/{knowledgeQuestionId:guid}/assign
assignKnowledgeQuestionparseKnowledgeQuestionMutation
POST
/api/modules/knowledge-core/questions/{knowledgeQuestionId:guid}/answer
answerKnowledgeQuestionparseKnowledgeQuestionMutation
POST
/api/modules/knowledge-core/questions/{knowledgeQuestionId:guid}/convert
convertKnowledgeQuestionparseKnowledgeQuestionMutation
POST
/api/modules/knowledge-core/{recordId:guid}/feedback
recordKnowledgeFeedbackparseKnowledgeFeedbackMutation
GET
/api/modules/knowledge-core/{recordId:guid}/feedback
getKnowledgeFeedbackparseKnowledgeFeedbackSummary
GET
/api/modules/knowledge-core/gaps
getKnowledgeGapsparseKnowledgeGaps
GET
/api/modules/knowledge-core/support-learning/candidates
Use the typed transport/clientUse the returned typed contract
POST
/api/modules/knowledge-core/support-learning/candidates
Use the typed transport/clientUse the returned typed contract
Chat rooms 9 headless operations

Integration: page-module · Native key: module.chat-rooms
API roots: /api/modules/chat-rooms

Exact HTTP routeCurrent browser functionResponse parser
GET
/api/modules/chat-rooms
listChatRoomsparseChatRoomsList
GET
/api/modules/chat-rooms/{recordId:guid}
getChatRoomparseChatRoomDetail
POST
/api/modules/chat-rooms
createChatRoomparseChatRoomMutation
PUT
/api/modules/chat-rooms/{recordId:guid}
updateChatRoomparseChatRoomMutation
POST
/api/modules/chat-rooms/{recordId:guid}/messages
postChatMessageparseChatRoomMutation
PUT
/api/modules/chat-rooms/{recordId:guid}/messages/{chatMessageId:guid}/reaction
setChatReactionparseChatRoomMutation
PUT
/api/modules/chat-rooms/{recordId:guid}/members/{memberUserId:guid}
setChatRoomMemberparseChatRoomMutation
PUT
/api/modules/chat-rooms/{recordId:guid}/read
markChatRoomReadparseChatRoomMutation
PUT
/api/modules/chat-rooms/{recordId:guid}/favorite
setChatRoomFavoriteparseChatRoomMutation
Discussion boards 10 headless operations

Integration: page-module · Native key: module.discussion-boards
API roots: /api/modules/discussion-boards

Exact HTTP routeCurrent browser functionResponse parser
GET
/api/modules/discussion-boards
listDiscussionBoardsparseDiscussionBoardsList
GET
/api/modules/discussion-boards/{recordId:guid}
getDiscussionBoardparseDiscussionBoardDetail
POST
/api/modules/discussion-boards
createDiscussionBoardparseDiscussionMutation
PUT
/api/modules/discussion-boards/{recordId:guid}
updateDiscussionBoardparseDiscussionMutation
POST
/api/modules/discussion-boards/{boardRecordId:guid}/topics
createDiscussionTopicparseDiscussionMutation
GET
/api/modules/discussion-boards/topics/{recordId:guid}
getDiscussionTopicparseDiscussionTopicDetail
PUT
/api/modules/discussion-boards/topics/{recordId:guid}
updateDiscussionTopicparseDiscussionMutation
POST
/api/modules/discussion-boards/topics/{topicRecordId:guid}/posts
postDiscussionReplyparseDiscussionMutation
PUT
/api/modules/discussion-boards/posts/{recordId:guid}
updateDiscussionPostparseDiscussionMutation
PUT
/api/modules/discussion-boards/records/{recordId:guid}/favorite
setDiscussionFavoriteparseDiscussionMutation
Mail reader 4 headless operations

Integration: page-module · Native key: module.mail-reader
API roots: /api/modules/mail-reader

Exact HTTP routeCurrent browser functionResponse parser
GET
/api/modules/mail-reader
listMailReaderMessagesparseMailReaderList
GET
/api/modules/mail-reader/{recordId:guid}
getMailReaderMessageparseMailReaderDetail
PUT
/api/modules/mail-reader/{recordId:guid}/read
setMailReaderReadparseMailReaderMutation
PUT
/api/modules/mail-reader/{recordId:guid}/favorite
setMailReaderFavoriteparseMailReaderMutation
Favorites 4 headless operations

Integration: page-module · Native key: module.favorites
API roots: /api/modules/favorites

Exact HTTP routeCurrent browser functionResponse parser
GET
/api/modules/favorites
listFavoritesparseFavoritesList
GET
/api/modules/favorites/{recordId:guid}
getFavoriteparseFavoriteDetail
PUT
/api/modules/favorites/{recordId:guid}/favorite
setFavoriteparseFavoriteMutation
PUT
/api/modules/favorites/{recordId:guid}/preferences
updateFavoritePreferencesparseFavoriteMutation
Notifications 4 headless operations

Integration: page-module · Native key: module.notifications
API roots: /api/modules/notifications

Exact HTTP routeCurrent browser functionResponse parser
GET
/api/modules/notifications
listNotificationsparseNotificationList
GET
/api/modules/notifications/{notificationId:guid}
getNotificationparseNotificationDetail
PUT
/api/modules/notifications/{notificationId:guid}/state
setNotificationStateparseNotificationMutation
PUT
/api/modules/notifications/{notificationId:guid}/source-favorite
setNotificationSourceFavoriteparseNotificationMutation
Dynamic/custom records 6 headless operations

Integration: page-module · Native key: module.dynamic-records
API roots: /api/modules/dynamic

Exact HTTP routeCurrent browser functionResponse parser
GET
/api/modules/dynamic/{moduleKey}/schema
getDynamicModuleSchemaparseDynamicModuleSchema
GET
/api/modules/dynamic/{moduleKey}
listDynamicModuleRecordsparseDynamicModuleList
GET
/api/modules/dynamic/{moduleKey}/{recordId:guid}
getDynamicModuleRecordparseDynamicModuleDetail
POST
/api/modules/dynamic/{moduleKey}
createDynamicModuleRecordparseDynamicModuleMutation
PUT
/api/modules/dynamic/{moduleKey}/{recordId:guid}
updateDynamicModuleRecordparseDynamicModuleMutation
PUT
/api/modules/dynamic/{moduleKey}/{recordId:guid}/favorite
setDynamicModuleFavoriteparseDynamicModuleMutation
ActiveWorkplace 11 headless operations

Integration: page-module · Native key: module.active-workplace
API roots: /api/modules/active-workplace

Exact HTTP routeCurrent browser functionResponse parser
GET
/api/modules/active-workplace
listActiveWorkplacesparseActiveWorkplaceList
POST
/api/modules/active-workplace
createActiveWorkplaceparseActiveWorkplaceMutation
GET
/api/modules/active-workplace/{activeWorkplaceId:guid}
getActiveWorkplaceparseActiveWorkplaceDetail
PATCH
/api/modules/active-workplace/{activeWorkplaceId:guid}
updateActiveWorkplaceparseActiveWorkplaceMutation
POST
/api/modules/active-workplace/{activeWorkplaceId:guid}/status
setActiveWorkplaceStatusparseActiveWorkplaceMutation
GET
/api/modules/active-workplace/{activeWorkplaceId:guid}/participants/catalog
getActiveWorkplaceParticipantCatalogparseActiveWorkplaceCatalog
POST
/api/modules/active-workplace/{activeWorkplaceId:guid}/participants
addActiveWorkplaceParticipantparseActiveWorkplaceMutation
DELETE
/api/modules/active-workplace/{activeWorkplaceId:guid}/participants/{activeWorkplaceParticipantId:guid}
removeActiveWorkplaceParticipantparseActiveWorkplaceMutation
POST
/api/modules/active-workplace/{activeWorkplaceId:guid}/activity
recordActiveWorkplaceActivityparseActiveWorkplaceMutation
POST
/api/modules/active-workplace/{activeWorkplaceId:guid}/graph/refresh
refreshActiveWorkplaceGraphparseActiveWorkplaceMutation
GET
/api/modules/active-workplace/{activeWorkplaceId:guid}/playback
getActiveWorkplacePlaybackparseActiveWorkplacePlayback
Record relations 9 headless operations

Integration: page-module · Native key: module.record-graph
API roots: /api/modules/record-graph

Exact HTTP routeCurrent browser functionResponse parser
GET
/api/modules/record-graph/records
searchRecordGraphparseRecordGraphSearch
GET
/api/modules/record-graph/{recordId:guid}
getRecordGraphparseRecordGraph
PUT
/api/modules/record-graph/{recordId:guid}/relations
addRecordGraphRelationparseRecordGraphMutation
DELETE
/api/modules/record-graph/relations/{recordRelationId:guid}
removeRecordGraphRelationparseRecordGraphMutation
PUT
/api/modules/record-graph/{recordId:guid}/favorite
setRecordGraphFavoriteparseFavoriteMutation
GET
/api/modules/record-graph/{recordId:guid}/knowledge
getRelatedKnowledgeparseRelatedKnowledge
GET
/api/modules/record-graph/{recordId:guid}/knowledge/candidates
getContextualKnowledgeparseContextualKnowledge
PUT
/api/modules/record-graph/{recordId:guid}/knowledge
linkKnowledgeToRecordparseKnowledgeRelationMutation
DELETE
/api/modules/record-graph/knowledge-relations/{recordRelationId:guid}
unlinkKnowledgeFromRecordparseKnowledgeRelationMutation
Record activity 3 headless operations

Integration: page-module · Native key: module.record-activity
API roots: /api/modules/record-activity

Exact HTTP routeCurrent browser functionResponse parser
GET
/api/modules/record-activity/records
searchRecordActivityparseRecordActivitySearch
GET
/api/modules/record-activity/{recordId:guid}
getRecordActivityparseRecordActivity
PUT
/api/modules/record-activity/{recordId:guid}/favorite
setRecordActivityFavoriteparseFavoriteMutation
Ai Insights API 3 headless operations

Integration: api-surface · Native key: module.ai-insights
API roots: /api/modules/ai-insights

Exact HTTP routeCurrent browser functionResponse parser
GET
/api/modules/ai-insights
listAiInsightsparseAiInsightList
GET
/api/modules/ai-insights/{insightId:guid}
getAiInsightparseAiInsightDetail
PUT
/api/modules/ai-insights/{insightId:guid}/state
setAiInsightStateparseAiInsightState
Payments Module API 7 headless operations

Integration: api-surface · Native key: Not a page block
API roots: /api/modules/payments

Exact HTTP routeCurrent browser functionResponse parser
GET
/api/modules/payments/settings
getTenantPaymentSettingsparseTenantPaymentSettings
PUT
/api/modules/payments/settings/{moduleKey}
updateTenantPaymentPolicyparseTenantPaymentMutation
PUT
/api/modules/payments/connectors
upsertTenantPaymentConnectorparseTenantPaymentMutation
DELETE
/api/modules/payments/connectors/{connectorId:guid}
deactivateTenantPaymentConnectorparseTenantPaymentMutation
GET
/api/modules/payments/methods
Use the typed transport/clientUse the returned typed contract
GET
/api/modules/payments/records/{recordId:guid}
getTenantRecordPaymentsparseTenantRecordPaymentSummary
POST
/api/modules/payments/records/{recordId:guid}/charges
createTenantRecordChargeparseTenantPaymentMutation
Copy the searchable styled/unstyled operation directory

import { useMemo, useState } from "react";
import { headlessCapabilityRecipes } from "./HeadlessCapabilityRecipes.generated";

export const HeadlessOperationDirectory = ({ styled = false }: { readonly styled?: boolean }) => {
  const [query, setQuery] = useState("");
  const recipes = useMemo(() => {
    const needle = query.trim().toLowerCase();
    return needle ? headlessCapabilityRecipes.filter((recipe) => [recipe.title, recipe.slug, ...recipe.apiBasePaths, ...recipe.operations.flatMap((operation) => [operation.method, operation.route, ...operation.browserFunctions])].some((value) => value.toLowerCase().includes(needle))) : headlessCapabilityRecipes;
  }, [query]);
  return <section className={styled ? "bwhq-headless-directory" : undefined}>
    <header><h1>Headless capability operations</h1><label>Search capability, route, or function<input type="search" value={query} onChange={(event) => setQuery(event.target.value)} /></label></header>
    {recipes.map((recipe) => <details key={recipe.slug}><summary><strong>{recipe.title}</strong> <span>{recipe.operations.length} operations</span></summary><p>{recipe.integrationKind} · {recipe.nativeComponentKey || "No native page block"}</p>{recipe.operations.length === 0 ? <p>{recipe.integrationNote}</p> : <table><thead><tr><th>HTTP</th><th>Browser function</th><th>Parser</th></tr></thead><tbody>{recipe.operations.map((operation) => <tr key={`${operation.method} ${operation.route}`}><td><strong>{operation.method}</strong><br /><code>{operation.route}</code></td><td>{operation.browserFunctions.join(", ") || "Use typed transport/client"}</td><td>{operation.parsers.join(", ") || "See typed client contract"}</td></tr>)}</tbody></table>}</details>)}
  </section>;
};

export const UnstyledHeadlessOperationDirectory = () => <HeadlessOperationDirectory />;
export const StyledHeadlessOperationDirectory = () => <HeadlessOperationDirectory styled />;
Copy the complete machine-readable headless recipes
export interface HeadlessOperationRecipe {
  readonly method: string;
  readonly route: string;
  readonly browserFunctions: readonly string[];
  readonly parsers: readonly string[];
  readonly procedures: readonly string[];
}

export interface HeadlessCapabilityRecipe {
  readonly slug: string;
  readonly title: string;
  readonly integrationKind: "page-module" | "shell-component" | "background-service" | "api-surface";
  readonly nativeComponentKey: string | null;
  readonly apiBasePaths: readonly string[];
  readonly clientMethods: readonly string[];
  readonly operations: readonly HeadlessOperationRecipe[];
  readonly integrationNote: string;
}

export const headlessCapabilityRecipes = [
  {
    "slug": "universal-inbox",
    "title": "Universal Inbox",
    "integrationKind": "shell-component",
    "nativeComponentKey": null,
    "apiBasePaths": [
      "/api/inbox",
      "/api/inbox/items"
    ],
    "clientMethods": [
      "list",
      "get",
      "badge",
      "notifications",
      "deliveryDebug",
      "retryDelivery",
      "setReadState",
      "setStatus",
      "setPriority",
      "setAssignment",
      "getEmailTicketingSettings",
      "setEmailTicketing",
      "decideWorkflowApproval"
    ],
    "operations": [
      {
        "method": "GET",
        "route": "/api/inbox/items",
        "browserFunctions": [],
        "parsers": [],
        "procedures": [
          "sp_Inbox_GetQueueSecured"
        ]
      },
      {
        "method": "GET",
        "route": "/api/inbox/email-channels/ticketing",
        "browserFunctions": [],
        "parsers": [],
        "procedures": [
          "sp_Inbox_GetEmailTicketingSettingsSecured"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/inbox/email-channels/{channelConnectionId:guid}/ticketing",
        "browserFunctions": [],
        "parsers": [],
        "procedures": [
          "sp_Inbox_SetEmailTicketingSecured"
        ]
      },
      {
        "method": "GET",
        "route": "/api/inbox/items/{inboxItemId:guid}",
        "browserFunctions": [],
        "parsers": [],
        "procedures": [
          "sp_Inbox_GetItemDetailSecured"
        ]
      },
      {
        "method": "GET",
        "route": "/api/inbox/badge",
        "browserFunctions": [],
        "parsers": [],
        "procedures": [
          "sp_GetInboxBadgeSecured"
        ]
      },
      {
        "method": "GET",
        "route": "/api/inbox/notifications",
        "browserFunctions": [],
        "parsers": [],
        "procedures": [
          "sp_GetInboxNotificationsSecured"
        ]
      },
      {
        "method": "GET",
        "route": "/api/inbox/delivery/debug",
        "browserFunctions": [],
        "parsers": [],
        "procedures": [
          "sp_GetDeliveryDebugSecured"
        ]
      },
      {
        "method": "POST",
        "route": "/api/inbox/delivery/{outboundMessageId:guid}/retry",
        "browserFunctions": [],
        "parsers": [],
        "procedures": [
          "sp_RetryOutboundMessage"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/inbox/items/{inboxItemId:guid}/human-state",
        "browserFunctions": [],
        "parsers": [],
        "procedures": [
          "sp_Inbox_MarkRead"
        ]
      },
      {
        "method": "POST",
        "route": "/api/inbox/items/{inboxItemId:guid}/workflow-approval",
        "browserFunctions": [],
        "parsers": [],
        "procedures": []
      }
    ],
    "integrationNote": "Use the current typed client or the exact operations listed here."
  },
  {
    "slug": "checklists-signoffs",
    "title": "Checklists & Signoffs",
    "integrationKind": "page-module",
    "nativeComponentKey": "module.checklists-signoffs",
    "apiBasePaths": [
      "/api/modules/checklists-signoffs"
    ],
    "clientMethods": [],
    "operations": [
      {
        "method": "GET",
        "route": "/api/modules/checklists-signoffs/templates",
        "browserFunctions": [
          "listChecklistTemplates"
        ],
        "parsers": [
          "parseChecklistTemplateList"
        ],
        "procedures": [
          "sp_Checklists_ListTemplatesSecured"
        ]
      },
      {
        "method": "POST",
        "route": "/api/modules/checklists-signoffs/templates",
        "browserFunctions": [
          "createChecklistTemplate"
        ],
        "parsers": [
          "parseChecklistMutation"
        ],
        "procedures": [
          "sp_Checklists_CreateTemplateSecured"
        ]
      },
      {
        "method": "GET",
        "route": "/api/modules/checklists-signoffs/runs",
        "browserFunctions": [
          "listChecklistRuns"
        ],
        "parsers": [
          "parseChecklistRunList"
        ],
        "procedures": [
          "sp_Checklists_ListRunsSecured"
        ]
      },
      {
        "method": "GET",
        "route": "/api/modules/checklists-signoffs/runs/{checklistRunId:guid}",
        "browserFunctions": [
          "getChecklistRun"
        ],
        "parsers": [
          "parseChecklistRunDetail"
        ],
        "procedures": [
          "sp_Checklists_GetRunSecured"
        ]
      },
      {
        "method": "POST",
        "route": "/api/modules/checklists-signoffs/runs",
        "browserFunctions": [
          "startChecklistRun"
        ],
        "parsers": [
          "parseChecklistMutation"
        ],
        "procedures": [
          "sp_Checklists_StartRunSecured"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/modules/checklists-signoffs/items/{checklistRunItemId:guid}",
        "browserFunctions": [
          "updateChecklistItem"
        ],
        "parsers": [
          "parseChecklistMutation"
        ],
        "procedures": [
          "sp_Checklists_UpdateItemSecured"
        ]
      },
      {
        "method": "POST",
        "route": "/api/modules/checklists-signoffs/items/{checklistRunItemId:guid}/proof",
        "browserFunctions": [
          "attachChecklistProof"
        ],
        "parsers": [
          "parseChecklistMutation"
        ],
        "procedures": [
          "sp_Checklists_AttachProofSecured"
        ]
      },
      {
        "method": "DELETE",
        "route": "/api/modules/checklists-signoffs/proof/{checklistItemEvidenceId:guid}",
        "browserFunctions": [
          "removeChecklistProof"
        ],
        "parsers": [
          "parseChecklistMutation"
        ],
        "procedures": [
          "sp_Checklists_RemoveProofSecured"
        ]
      },
      {
        "method": "POST",
        "route": "/api/modules/checklists-signoffs/runs/{checklistRunId:guid}/submit",
        "browserFunctions": [
          "submitChecklistForSignoff"
        ],
        "parsers": [
          "parseChecklistMutation"
        ],
        "procedures": [
          "sp_Checklists_SubmitForSignoffSecured"
        ]
      }
    ],
    "integrationNote": "Use the current typed client or the exact operations listed here."
  },
  {
    "slug": "goclaw",
    "title": "GoClaw virtual assistant",
    "integrationKind": "shell-component",
    "nativeComponentKey": null,
    "apiBasePaths": [
      "/api/goclaw/agents",
      "/api/goclaw/approvals"
    ],
    "clientMethods": [
      "list",
      "approve",
      "reject",
      "takeOver",
      "retry"
    ],
    "operations": [
      {
        "method": "PUT",
        "route": "/api/goclaw/agents/{goClawAgentId:guid}/authority",
        "browserFunctions": [],
        "parsers": [],
        "procedures": []
      },
      {
        "method": "GET",
        "route": "/api/goclaw/approvals",
        "browserFunctions": [],
        "parsers": [],
        "procedures": []
      },
      {
        "method": "POST",
        "route": "/api/goclaw/approvals/{suggestionBatchId:guid}/approve",
        "browserFunctions": [],
        "parsers": [],
        "procedures": []
      },
      {
        "method": "POST",
        "route": "/api/goclaw/approvals/{suggestionBatchId:guid}/reject",
        "browserFunctions": [],
        "parsers": [],
        "procedures": []
      },
      {
        "method": "POST",
        "route": "/api/goclaw/approvals/{suggestionBatchId:guid}/take-over",
        "browserFunctions": [],
        "parsers": [],
        "procedures": []
      },
      {
        "method": "POST",
        "route": "/api/goclaw/approvals/{suggestionBatchId:guid}/retry",
        "browserFunctions": [],
        "parsers": [],
        "procedures": []
      }
    ],
    "integrationNote": "Use the current typed client or the exact operations listed here."
  },
  {
    "slug": "ai-insights",
    "title": "AI Insights",
    "integrationKind": "background-service",
    "nativeComponentKey": null,
    "apiBasePaths": [],
    "clientMethods": [],
    "operations": [],
    "integrationNote": "This is a scheduled/background capability. Use its governed service and secured feed contracts when exposed; do not invent a browser mutation endpoint."
  },
  {
    "slug": "contacts",
    "title": "Contacts",
    "integrationKind": "page-module",
    "nativeComponentKey": "module.contacts",
    "apiBasePaths": [
      "/api/modules/contacts"
    ],
    "clientMethods": [],
    "operations": [
      {
        "method": "GET",
        "route": "/api/modules/contacts",
        "browserFunctions": [
          "listContacts"
        ],
        "parsers": [
          "parseContactList"
        ],
        "procedures": [
          "sp_Contacts_ListSecured"
        ]
      },
      {
        "method": "GET",
        "route": "/api/modules/contacts/{recordId:guid}",
        "browserFunctions": [
          "getContact"
        ],
        "parsers": [
          "parseContactDetail"
        ],
        "procedures": [
          "sp_Contacts_GetSecured"
        ]
      },
      {
        "method": "POST",
        "route": "/api/modules/contacts",
        "browserFunctions": [
          "createContact"
        ],
        "parsers": [
          "parseContactMutation"
        ],
        "procedures": [
          "sp_Contacts_CreateSecured"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/modules/contacts/{recordId:guid}",
        "browserFunctions": [
          "updateContact"
        ],
        "parsers": [
          "parseContactMutation"
        ],
        "procedures": [
          "sp_Contacts_UpdateSecured"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/modules/contacts/{recordId:guid}/favorite",
        "browserFunctions": [
          "setContactFavorite"
        ],
        "parsers": [
          "parseContactMutation"
        ],
        "procedures": [
          "sp_Contacts_SetFavoriteSecured"
        ]
      }
    ],
    "integrationNote": "Use the current typed client or the exact operations listed here."
  },
  {
    "slug": "work-orders",
    "title": "Work Orders",
    "integrationKind": "page-module",
    "nativeComponentKey": "module.work-orders",
    "apiBasePaths": [
      "/api/modules/work-orders"
    ],
    "clientMethods": [],
    "operations": [
      {
        "method": "GET",
        "route": "/api/modules/work-orders",
        "browserFunctions": [
          "listWorkOrders"
        ],
        "parsers": [
          "parseWorkOrderList"
        ],
        "procedures": [
          "sp_WorkOrders_ListSecured"
        ]
      },
      {
        "method": "GET",
        "route": "/api/modules/work-orders/{recordId:guid}",
        "browserFunctions": [
          "getWorkOrder"
        ],
        "parsers": [
          "parseWorkOrderDetail"
        ],
        "procedures": [
          "sp_WorkOrders_GetSecured"
        ]
      },
      {
        "method": "POST",
        "route": "/api/modules/work-orders",
        "browserFunctions": [
          "createWorkOrder"
        ],
        "parsers": [
          "parseWorkOrderMutation"
        ],
        "procedures": [
          "sp_WorkOrders_CreateSecured"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/modules/work-orders/{recordId:guid}",
        "browserFunctions": [
          "updateWorkOrder"
        ],
        "parsers": [
          "parseWorkOrderMutation"
        ],
        "procedures": [
          "sp_WorkOrders_UpdateSecured"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/modules/work-orders/{recordId:guid}/status",
        "browserFunctions": [
          "setWorkOrderStatus"
        ],
        "parsers": [
          "parseWorkOrderMutation"
        ],
        "procedures": [
          "sp_WorkOrders_SetStatusSecured"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/modules/work-orders/{recordId:guid}/assignment",
        "browserFunctions": [
          "assignWorkOrder"
        ],
        "parsers": [
          "parseWorkOrderMutation"
        ],
        "procedures": [
          "sp_WorkOrders_AssignSecured"
        ]
      }
    ],
    "integrationNote": "Use the current typed client or the exact operations listed here."
  },
  {
    "slug": "reservations",
    "title": "Reservations",
    "integrationKind": "page-module",
    "nativeComponentKey": "module.reservations",
    "apiBasePaths": [
      "/api/modules/reservations"
    ],
    "clientMethods": [],
    "operations": [
      {
        "method": "GET",
        "route": "/api/modules/reservations/products",
        "browserFunctions": [
          "listReservationProducts"
        ],
        "parsers": [
          "parseReservationProductList"
        ],
        "procedures": [
          "sp_ReservationProducts_ListSecured"
        ]
      },
      {
        "method": "POST",
        "route": "/api/modules/reservations/products",
        "browserFunctions": [
          "saveReservationProduct"
        ],
        "parsers": [
          "parseReservationMutation"
        ],
        "procedures": [
          "sp_ReservationProducts_UpsertSecured"
        ]
      },
      {
        "method": "GET",
        "route": "/api/modules/reservations",
        "browserFunctions": [
          "listReservations"
        ],
        "parsers": [
          "parseReservationList"
        ],
        "procedures": [
          "sp_Reservations_ListSecured"
        ]
      },
      {
        "method": "GET",
        "route": "/api/modules/reservations/{recordId:guid}",
        "browserFunctions": [
          "getReservation"
        ],
        "parsers": [
          "parseReservationDetail"
        ],
        "procedures": [
          "sp_Reservations_GetSecured"
        ]
      },
      {
        "method": "POST",
        "route": "/api/modules/reservations/purchase",
        "browserFunctions": [
          "purchaseReservation"
        ],
        "parsers": [
          "parseReservationMutation"
        ],
        "procedures": [
          "sp_Reservations_PurchaseSecured"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/modules/reservations/{recordId:guid}/status",
        "browserFunctions": [
          "setReservationStatus"
        ],
        "parsers": [
          "parseReservationMutation"
        ],
        "procedures": [
          "sp_Reservations_SetStatusSecured"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/modules/reservations/{recordId:guid}/followups",
        "browserFunctions": [
          "updateReservationFollowup"
        ],
        "parsers": [
          "parseReservationMutation"
        ],
        "procedures": [
          "sp_ReservationFollowups_UpdateSecured"
        ]
      }
    ],
    "integrationNote": "Use the current typed client or the exact operations listed here."
  },
  {
    "slug": "calendar",
    "title": "Calendar",
    "integrationKind": "page-module",
    "nativeComponentKey": "module.calendar",
    "apiBasePaths": [
      "/api/modules/calendar"
    ],
    "clientMethods": [],
    "operations": [
      {
        "method": "GET",
        "route": "/api/modules/calendar",
        "browserFunctions": [
          "listCalendarEvents"
        ],
        "parsers": [
          "parseCalendarEventList"
        ],
        "procedures": [
          "sp_Calendar_ListSecured"
        ]
      },
      {
        "method": "GET",
        "route": "/api/modules/calendar/{recordId:guid}",
        "browserFunctions": [
          "getCalendarEvent"
        ],
        "parsers": [
          "parseCalendarEventDetail"
        ],
        "procedures": [
          "sp_Calendar_GetSecured"
        ]
      },
      {
        "method": "POST",
        "route": "/api/modules/calendar",
        "browserFunctions": [
          "createCalendarEvent"
        ],
        "parsers": [
          "parseCalendarMutation"
        ],
        "procedures": [
          "sp_Calendar_CreateSecured"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/modules/calendar/{recordId:guid}",
        "browserFunctions": [
          "updateCalendarEvent"
        ],
        "parsers": [
          "parseCalendarMutation"
        ],
        "procedures": [
          "sp_Calendar_UpdateSecured"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/modules/calendar/{recordId:guid}/favorite",
        "browserFunctions": [
          "setCalendarFavorite"
        ],
        "parsers": [
          "parseCalendarMutation"
        ],
        "procedures": [
          "sp_Calendar_SetFavoriteSecured"
        ]
      }
    ],
    "integrationNote": "Use the current typed client or the exact operations listed here."
  },
  {
    "slug": "files",
    "title": "Files & attachments",
    "integrationKind": "page-module",
    "nativeComponentKey": "module.files",
    "apiBasePaths": [
      "/api/modules/files"
    ],
    "clientMethods": [],
    "operations": [
      {
        "method": "GET",
        "route": "/api/modules/files",
        "browserFunctions": [
          "listFiles"
        ],
        "parsers": [
          "parseFileList"
        ],
        "procedures": [
          "sp_Files_ListSecured"
        ]
      },
      {
        "method": "GET",
        "route": "/api/modules/files/{recordId:guid}",
        "browserFunctions": [
          "getFile"
        ],
        "parsers": [
          "parseFileDetail"
        ],
        "procedures": [
          "sp_Files_GetSecured"
        ]
      },
      {
        "method": "POST",
        "route": "/api/modules/files/upload",
        "browserFunctions": [
          "uploadFile"
        ],
        "parsers": [
          "parseFileMutation"
        ],
        "procedures": [
          "sp_Files_CreateSecured"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/modules/files/{recordId:guid}",
        "browserFunctions": [
          "updateFile"
        ],
        "parsers": [
          "parseFileMutation"
        ],
        "procedures": [
          "sp_Files_UpdateSecured"
        ]
      },
      {
        "method": "POST",
        "route": "/api/modules/files/{recordId:guid}/attachments",
        "browserFunctions": [
          "attachFile"
        ],
        "parsers": [
          "parseFileMutation"
        ],
        "procedures": [
          "sp_Files_AttachSecured"
        ]
      },
      {
        "method": "DELETE",
        "route": "/api/modules/files/{recordId:guid}/attachments/{attachmentId:guid}",
        "browserFunctions": [
          "detachFile"
        ],
        "parsers": [
          "parseFileMutation"
        ],
        "procedures": [
          "sp_Files_DetachSecured"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/modules/files/{recordId:guid}/favorite",
        "browserFunctions": [
          "setFileFavorite"
        ],
        "parsers": [
          "parseFileMutation"
        ],
        "procedures": [
          "sp_Files_SetFavoriteSecured"
        ]
      },
      {
        "method": "GET",
        "route": "/api/modules/files/{recordId:guid}/content",
        "browserFunctions": [
          "downloadFileContent"
        ],
        "parsers": [],
        "procedures": [
          "sp_Files_ListSecured",
          "sp_Files_GetSecured",
          "sp_Files_CreateSecured",
          "sp_Files_UpdateSecured",
          "sp_Files_AttachSecured",
          "sp_Files_DetachSecured",
          "sp_Files_SetFavoriteSecured",
          "sp_Files_GetDownloadSecured"
        ]
      }
    ],
    "integrationNote": "Use the current typed client or the exact operations listed here."
  },
  {
    "slug": "conversations",
    "title": "Conversations & messages",
    "integrationKind": "page-module",
    "nativeComponentKey": "module.conversations",
    "apiBasePaths": [
      "/api/modules/conversations"
    ],
    "clientMethods": [],
    "operations": [
      {
        "method": "GET",
        "route": "/api/modules/conversations",
        "browserFunctions": [
          "listConversations"
        ],
        "parsers": [
          "parseConversationList"
        ],
        "procedures": [
          "sp_Conversations_ListSecured"
        ]
      },
      {
        "method": "GET",
        "route": "/api/modules/conversations/{recordId:guid}",
        "browserFunctions": [
          "getConversation"
        ],
        "parsers": [
          "parseConversationDetail"
        ],
        "procedures": [
          "sp_Conversations_GetSecured"
        ]
      },
      {
        "method": "POST",
        "route": "/api/modules/conversations",
        "browserFunctions": [
          "createConversation"
        ],
        "parsers": [
          "parseConversationMutation"
        ],
        "procedures": [
          "sp_Conversations_CreateSecured"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/modules/conversations/{recordId:guid}",
        "browserFunctions": [
          "updateConversation"
        ],
        "parsers": [
          "parseConversationMutation"
        ],
        "procedures": [
          "sp_Conversations_UpdateSecured"
        ]
      },
      {
        "method": "POST",
        "route": "/api/modules/conversations/{recordId:guid}/messages",
        "browserFunctions": [
          "postConversationMessage"
        ],
        "parsers": [
          "parseConversationMutation"
        ],
        "procedures": [
          "sp_Conversations_ReplySecured"
        ]
      },
      {
        "method": "POST",
        "route": "/api/modules/conversations/direct",
        "browserFunctions": [],
        "parsers": [],
        "procedures": [
          "sp_Conversations_SendDirectSecured"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/modules/conversations/{recordId:guid}/favorite",
        "browserFunctions": [
          "setConversationFavorite"
        ],
        "parsers": [
          "parseConversationMutation"
        ],
        "procedures": [
          "sp_Conversations_SetFavoriteSecured"
        ]
      }
    ],
    "integrationNote": "Use the current typed client or the exact operations listed here."
  },
  {
    "slug": "company-news",
    "title": "Company news",
    "integrationKind": "page-module",
    "nativeComponentKey": "module.company-news",
    "apiBasePaths": [
      "/api/modules/company-news"
    ],
    "clientMethods": [],
    "operations": [
      {
        "method": "GET",
        "route": "/api/modules/company-news",
        "browserFunctions": [
          "listCompanyNews"
        ],
        "parsers": [
          "parseCompanyNewsList"
        ],
        "procedures": [
          "sp_CompanyNews_ListSecured"
        ]
      },
      {
        "method": "GET",
        "route": "/api/modules/company-news/{recordId:guid}",
        "browserFunctions": [
          "getCompanyNews"
        ],
        "parsers": [
          "parseCompanyNewsDetail"
        ],
        "procedures": [
          "sp_CompanyNews_GetSecured"
        ]
      },
      {
        "method": "POST",
        "route": "/api/modules/company-news",
        "browserFunctions": [
          "createCompanyNews"
        ],
        "parsers": [
          "parseCompanyNewsMutation"
        ],
        "procedures": [
          "sp_CompanyNews_CreateSecured"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/modules/company-news/{recordId:guid}",
        "browserFunctions": [
          "updateCompanyNews"
        ],
        "parsers": [
          "parseCompanyNewsMutation"
        ],
        "procedures": [
          "sp_CompanyNews_UpdateSecured"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/modules/company-news/{recordId:guid}/favorite",
        "browserFunctions": [
          "setCompanyNewsFavorite"
        ],
        "parsers": [
          "parseCompanyNewsMutation"
        ],
        "procedures": [
          "sp_CompanyNews_SetFavoriteSecured"
        ]
      }
    ],
    "integrationNote": "Use the current typed client or the exact operations listed here."
  },
  {
    "slug": "knowledge-core",
    "title": "Knowledge Core",
    "integrationKind": "page-module",
    "nativeComponentKey": "module.knowledge-articles",
    "apiBasePaths": [
      "/api/modules/knowledge-articles",
      "/api/modules/knowledge-core"
    ],
    "clientMethods": [],
    "operations": [
      {
        "method": "GET",
        "route": "/api/modules/knowledge-articles",
        "browserFunctions": [
          "listKnowledgeArticles"
        ],
        "parsers": [
          "parseKnowledgeArticlesList"
        ],
        "procedures": [
          "sp_KnowledgeArticles_ListSecured"
        ]
      },
      {
        "method": "GET",
        "route": "/api/modules/knowledge-articles/{recordId:guid}",
        "browserFunctions": [
          "getKnowledgeArticle"
        ],
        "parsers": [
          "parseKnowledgeArticleDetail"
        ],
        "procedures": [
          "sp_KnowledgeArticles_GetSecured"
        ]
      },
      {
        "method": "POST",
        "route": "/api/modules/knowledge-articles",
        "browserFunctions": [
          "createKnowledgeArticle"
        ],
        "parsers": [
          "parseKnowledgeArticleMutation"
        ],
        "procedures": [
          "sp_KnowledgeArticles_CreateSecured"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/modules/knowledge-articles/{recordId:guid}",
        "browserFunctions": [
          "updateKnowledgeArticle"
        ],
        "parsers": [
          "parseKnowledgeArticleMutation"
        ],
        "procedures": [
          "sp_KnowledgeArticles_UpdateSecured"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/modules/knowledge-articles/{recordId:guid}/favorite",
        "browserFunctions": [
          "setKnowledgeArticleFavorite"
        ],
        "parsers": [
          "parseKnowledgeArticleMutation"
        ],
        "procedures": [
          "sp_KnowledgeArticles_SetFavoriteSecured"
        ]
      },
      {
        "method": "GET",
        "route": "/api/modules/knowledge-core",
        "browserFunctions": [
          "listKnowledgeCore"
        ],
        "parsers": [
          "parseKnowledgeCoreList"
        ],
        "procedures": [
          "sp_kc_ListKnowledgeItemsSecured"
        ]
      },
      {
        "method": "GET",
        "route": "/api/modules/knowledge-core/{recordId:guid}",
        "browserFunctions": [
          "getKnowledgeCore"
        ],
        "parsers": [
          "parseKnowledgeCoreDetail"
        ],
        "procedures": [
          "sp_kc_GetKnowledgeItemSecured"
        ]
      },
      {
        "method": "POST",
        "route": "/api/modules/knowledge-core",
        "browserFunctions": [
          "createKnowledgeCore"
        ],
        "parsers": [
          "parseKnowledgeCoreMutation"
        ],
        "procedures": [
          "sp_kc_CreateKnowledgeItem"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/modules/knowledge-core/{recordId:guid}",
        "browserFunctions": [
          "updateKnowledgeCore"
        ],
        "parsers": [
          "parseKnowledgeCoreMutation"
        ],
        "procedures": [
          "sp_kc_UpdateKnowledgeItem"
        ]
      },
      {
        "method": "POST",
        "route": "/api/modules/knowledge-core/{recordId:guid}/publish",
        "browserFunctions": [
          "publishKnowledgeCore"
        ],
        "parsers": [
          "parseKnowledgeCoreMutation"
        ],
        "procedures": [
          "sp_kc_PublishKnowledgeItem"
        ]
      },
      {
        "method": "POST",
        "route": "/api/modules/knowledge-core/{recordId:guid}/archive",
        "browserFunctions": [
          "archiveKnowledgeCore"
        ],
        "parsers": [
          "parseKnowledgeCoreMutation"
        ],
        "procedures": [
          "sp_kc_ArchiveKnowledgeItem"
        ]
      },
      {
        "method": "GET",
        "route": "/api/modules/knowledge-core/{recordId:guid}/revisions",
        "browserFunctions": [
          "getKnowledgeCoreRevisions"
        ],
        "parsers": [
          "parseKnowledgeRevisions"
        ],
        "procedures": [
          "sp_kc_GetRevisionHistorySecured"
        ]
      },
      {
        "method": "POST",
        "route": "/api/modules/knowledge-core/{recordId:guid}/restore",
        "browserFunctions": [],
        "parsers": [],
        "procedures": [
          "sp_kc_RestoreRevisionAsDraft"
        ]
      },
      {
        "method": "GET",
        "route": "/api/modules/knowledge-core/collections",
        "browserFunctions": [
          "listKnowledgeCoreCollections"
        ],
        "parsers": [
          "parseKnowledgeCollections"
        ],
        "procedures": [
          "sp_kc_ListCollectionsSecured"
        ]
      },
      {
        "method": "POST",
        "route": "/api/modules/knowledge-core/collections",
        "browserFunctions": [],
        "parsers": [],
        "procedures": [
          "sp_kc_CreateCollection"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/modules/knowledge-core/collections/{collectionId:guid}",
        "browserFunctions": [],
        "parsers": [],
        "procedures": [
          "sp_kc_UpdateCollection"
        ]
      },
      {
        "method": "POST",
        "route": "/api/modules/knowledge-core/collections/{collectionId:guid}/items/{recordId:guid}",
        "browserFunctions": [],
        "parsers": [],
        "procedures": [
          "sp_kc_AddKnowledgeItemToCollection"
        ]
      },
      {
        "method": "DELETE",
        "route": "/api/modules/knowledge-core/collections/{collectionId:guid}/items/{recordId:guid}",
        "browserFunctions": [],
        "parsers": [],
        "procedures": [
          "sp_kc_RemoveKnowledgeItemFromCollection"
        ]
      },
      {
        "method": "GET",
        "route": "/api/modules/knowledge-core/{recordId:guid}/owners",
        "browserFunctions": [
          "getKnowledgeCoreOwners"
        ],
        "parsers": [
          "parseKnowledgeOwners"
        ],
        "procedures": [
          "sp_kc_GetKnowledgeOwnersSecured"
        ]
      },
      {
        "method": "POST",
        "route": "/api/modules/knowledge-core/{recordId:guid}/owners",
        "browserFunctions": [],
        "parsers": [],
        "procedures": [
          "sp_kc_SetKnowledgeOwner"
        ]
      },
      {
        "method": "DELETE",
        "route": "/api/modules/knowledge-core/owners/{knowledgeOwnerId:guid}",
        "browserFunctions": [],
        "parsers": [],
        "procedures": [
          "sp_kc_RemoveKnowledgeOwner"
        ]
      },
      {
        "method": "GET",
        "route": "/api/modules/knowledge-core/unowned",
        "browserFunctions": [],
        "parsers": [],
        "procedures": [
          "sp_kc_GetUnownedKnowledgeSecured"
        ]
      },
      {
        "method": "GET",
        "route": "/api/modules/knowledge-core/reviews",
        "browserFunctions": [
          "listKnowledgeReviews"
        ],
        "parsers": [
          "parseKnowledgeReviews"
        ],
        "procedures": [
          "sp_kc_ListDueReviewsSecured"
        ]
      },
      {
        "method": "POST",
        "route": "/api/modules/knowledge-core/reviews/{reviewCycleId:guid}/begin",
        "browserFunctions": [
          "beginKnowledgeReview"
        ],
        "parsers": [
          "parseKnowledgeReviewMutation"
        ],
        "procedures": [
          "sp_kc_BeginReview"
        ]
      },
      {
        "method": "POST",
        "route": "/api/modules/knowledge-core/reviews/{reviewCycleId:guid}/complete",
        "browserFunctions": [
          "completeKnowledgeReview"
        ],
        "parsers": [
          "parseKnowledgeReviewMutation"
        ],
        "procedures": [
          "sp_kc_CompleteReview"
        ]
      },
      {
        "method": "POST",
        "route": "/api/modules/knowledge-core/reviews/{reviewCycleId:guid}/reassign",
        "browserFunctions": [
          "reassignKnowledgeReview"
        ],
        "parsers": [
          "parseKnowledgeReviewMutation"
        ],
        "procedures": [
          "sp_kc_ReassignReview"
        ]
      },
      {
        "method": "GET",
        "route": "/api/modules/knowledge-core/health",
        "browserFunctions": [
          "getKnowledgeHealth"
        ],
        "parsers": [
          "parseKnowledgeHealth"
        ],
        "procedures": [
          "sp_kc_GetKnowledgeHealthSecured"
        ]
      },
      {
        "method": "GET",
        "route": "/api/modules/knowledge-core/questions",
        "browserFunctions": [
          "listKnowledgeQuestions"
        ],
        "parsers": [
          "parseKnowledgeQuestions"
        ],
        "procedures": [
          "sp_kc_GetOpenQuestionsSecured"
        ]
      },
      {
        "method": "POST",
        "route": "/api/modules/knowledge-core/questions",
        "browserFunctions": [
          "createKnowledgeQuestion"
        ],
        "parsers": [
          "parseKnowledgeQuestionMutation"
        ],
        "procedures": [
          "sp_kc_CreateQuestion"
        ]
      },
      {
        "method": "POST",
        "route": "/api/modules/knowledge-core/questions/{knowledgeQuestionId:guid}/assign",
        "browserFunctions": [
          "assignKnowledgeQuestion"
        ],
        "parsers": [
          "parseKnowledgeQuestionMutation"
        ],
        "procedures": [
          "sp_kc_AssignQuestion"
        ]
      },
      {
        "method": "POST",
        "route": "/api/modules/knowledge-core/questions/{knowledgeQuestionId:guid}/answer",
        "browserFunctions": [
          "answerKnowledgeQuestion"
        ],
        "parsers": [
          "parseKnowledgeQuestionMutation"
        ],
        "procedures": [
          "sp_kc_AnswerQuestion"
        ]
      },
      {
        "method": "POST",
        "route": "/api/modules/knowledge-core/questions/{knowledgeQuestionId:guid}/convert",
        "browserFunctions": [
          "convertKnowledgeQuestion"
        ],
        "parsers": [
          "parseKnowledgeQuestionMutation"
        ],
        "procedures": [
          "sp_kc_ConvertQuestionToKnowledge"
        ]
      },
      {
        "method": "POST",
        "route": "/api/modules/knowledge-core/{recordId:guid}/feedback",
        "browserFunctions": [
          "recordKnowledgeFeedback"
        ],
        "parsers": [
          "parseKnowledgeFeedbackMutation"
        ],
        "procedures": [
          "sp_kc_RecordFeedback"
        ]
      },
      {
        "method": "GET",
        "route": "/api/modules/knowledge-core/{recordId:guid}/feedback",
        "browserFunctions": [
          "getKnowledgeFeedback"
        ],
        "parsers": [
          "parseKnowledgeFeedbackSummary"
        ],
        "procedures": [
          "sp_kc_GetKnowledgeFeedbackSummarySecured"
        ]
      },
      {
        "method": "GET",
        "route": "/api/modules/knowledge-core/gaps",
        "browserFunctions": [
          "getKnowledgeGaps"
        ],
        "parsers": [
          "parseKnowledgeGaps"
        ],
        "procedures": [
          "sp_kc_GetKnowledgeGapsSecured"
        ]
      },
      {
        "method": "GET",
        "route": "/api/modules/knowledge-core/support-learning/candidates",
        "browserFunctions": [],
        "parsers": [],
        "procedures": [
          "sp_kc_GetSupportLearningCandidatesSecured"
        ]
      },
      {
        "method": "POST",
        "route": "/api/modules/knowledge-core/support-learning/candidates",
        "browserFunctions": [],
        "parsers": [],
        "procedures": [
          "sp_kc_CreateSupportResolutionCandidate"
        ]
      }
    ],
    "integrationNote": "Use the current typed client or the exact operations listed here."
  },
  {
    "slug": "web-links",
    "title": "Web links",
    "integrationKind": "page-module",
    "nativeComponentKey": "module.web-links",
    "apiBasePaths": [
      "/api/modules/web-links"
    ],
    "clientMethods": [],
    "operations": [
      {
        "method": "GET",
        "route": "/api/modules/web-links",
        "browserFunctions": [
          "listWebLinks"
        ],
        "parsers": [
          "parseWebLinksList"
        ],
        "procedures": [
          "sp_WebLinks_ListSecured"
        ]
      },
      {
        "method": "GET",
        "route": "/api/modules/web-links/{recordId:guid}",
        "browserFunctions": [
          "getWebLink"
        ],
        "parsers": [
          "parseWebLinkDetail"
        ],
        "procedures": [
          "sp_WebLinks_GetSecured"
        ]
      },
      {
        "method": "POST",
        "route": "/api/modules/web-links",
        "browserFunctions": [
          "createWebLink"
        ],
        "parsers": [
          "parseWebLinkMutation"
        ],
        "procedures": [
          "sp_WebLinks_CreateSecured"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/modules/web-links/{recordId:guid}",
        "browserFunctions": [
          "updateWebLink"
        ],
        "parsers": [
          "parseWebLinkMutation"
        ],
        "procedures": [
          "sp_WebLinks_UpdateSecured"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/modules/web-links/{recordId:guid}/favorite",
        "browserFunctions": [
          "setWebLinkFavorite"
        ],
        "parsers": [
          "parseWebLinkMutation"
        ],
        "procedures": [
          "sp_WebLinks_SetFavoriteSecured"
        ]
      }
    ],
    "integrationNote": "Use the current typed client or the exact operations listed here."
  },
  {
    "slug": "chat-rooms",
    "title": "Chat rooms",
    "integrationKind": "page-module",
    "nativeComponentKey": "module.chat-rooms",
    "apiBasePaths": [
      "/api/modules/chat-rooms"
    ],
    "clientMethods": [],
    "operations": [
      {
        "method": "GET",
        "route": "/api/modules/chat-rooms",
        "browserFunctions": [
          "listChatRooms"
        ],
        "parsers": [
          "parseChatRoomsList"
        ],
        "procedures": [
          "sp_ChatRooms_ListSecured"
        ]
      },
      {
        "method": "GET",
        "route": "/api/modules/chat-rooms/{recordId:guid}",
        "browserFunctions": [
          "getChatRoom"
        ],
        "parsers": [
          "parseChatRoomDetail"
        ],
        "procedures": [
          "sp_ChatRooms_GetSecured"
        ]
      },
      {
        "method": "POST",
        "route": "/api/modules/chat-rooms",
        "browserFunctions": [
          "createChatRoom"
        ],
        "parsers": [
          "parseChatRoomMutation"
        ],
        "procedures": [
          "sp_ChatRooms_CreateSecured"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/modules/chat-rooms/{recordId:guid}",
        "browserFunctions": [
          "updateChatRoom"
        ],
        "parsers": [
          "parseChatRoomMutation"
        ],
        "procedures": [
          "sp_ChatRooms_UpdateSecured"
        ]
      },
      {
        "method": "POST",
        "route": "/api/modules/chat-rooms/{recordId:guid}/messages",
        "browserFunctions": [
          "postChatMessage"
        ],
        "parsers": [
          "parseChatRoomMutation"
        ],
        "procedures": [
          "sp_ChatRooms_PostMessageSecured"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/modules/chat-rooms/{recordId:guid}/messages/{chatMessageId:guid}/reaction",
        "browserFunctions": [
          "setChatReaction"
        ],
        "parsers": [
          "parseChatRoomMutation"
        ],
        "procedures": [
          "sp_ChatRooms_SetReactionSecured"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/modules/chat-rooms/{recordId:guid}/members/{memberUserId:guid}",
        "browserFunctions": [
          "setChatRoomMember"
        ],
        "parsers": [
          "parseChatRoomMutation"
        ],
        "procedures": [
          "sp_ChatRooms_SetMemberSecured"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/modules/chat-rooms/{recordId:guid}/read",
        "browserFunctions": [
          "markChatRoomRead"
        ],
        "parsers": [
          "parseChatRoomMutation"
        ],
        "procedures": [
          "sp_ChatRooms_MarkReadSecured"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/modules/chat-rooms/{recordId:guid}/favorite",
        "browserFunctions": [
          "setChatRoomFavorite"
        ],
        "parsers": [
          "parseChatRoomMutation"
        ],
        "procedures": [
          "sp_ChatRooms_SetFavoriteSecured"
        ]
      }
    ],
    "integrationNote": "Use the current typed client or the exact operations listed here."
  },
  {
    "slug": "discussion-boards",
    "title": "Discussion boards",
    "integrationKind": "page-module",
    "nativeComponentKey": "module.discussion-boards",
    "apiBasePaths": [
      "/api/modules/discussion-boards"
    ],
    "clientMethods": [],
    "operations": [
      {
        "method": "GET",
        "route": "/api/modules/discussion-boards",
        "browserFunctions": [
          "listDiscussionBoards"
        ],
        "parsers": [
          "parseDiscussionBoardsList"
        ],
        "procedures": [
          "sp_DiscussionBoards_ListSecured"
        ]
      },
      {
        "method": "GET",
        "route": "/api/modules/discussion-boards/{recordId:guid}",
        "browserFunctions": [
          "getDiscussionBoard"
        ],
        "parsers": [
          "parseDiscussionBoardDetail"
        ],
        "procedures": [
          "sp_DiscussionBoards_GetBoardSecured"
        ]
      },
      {
        "method": "POST",
        "route": "/api/modules/discussion-boards",
        "browserFunctions": [
          "createDiscussionBoard"
        ],
        "parsers": [
          "parseDiscussionMutation"
        ],
        "procedures": [
          "sp_DiscussionBoards_CreateBoardSecured"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/modules/discussion-boards/{recordId:guid}",
        "browserFunctions": [
          "updateDiscussionBoard"
        ],
        "parsers": [
          "parseDiscussionMutation"
        ],
        "procedures": [
          "sp_DiscussionBoards_UpdateBoardSecured"
        ]
      },
      {
        "method": "POST",
        "route": "/api/modules/discussion-boards/{boardRecordId:guid}/topics",
        "browserFunctions": [
          "createDiscussionTopic"
        ],
        "parsers": [
          "parseDiscussionMutation"
        ],
        "procedures": [
          "sp_DiscussionBoards_CreateTopicSecured"
        ]
      },
      {
        "method": "GET",
        "route": "/api/modules/discussion-boards/topics/{recordId:guid}",
        "browserFunctions": [
          "getDiscussionTopic"
        ],
        "parsers": [
          "parseDiscussionTopicDetail"
        ],
        "procedures": [
          "sp_DiscussionBoards_GetTopicSecured"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/modules/discussion-boards/topics/{recordId:guid}",
        "browserFunctions": [
          "updateDiscussionTopic"
        ],
        "parsers": [
          "parseDiscussionMutation"
        ],
        "procedures": [
          "sp_DiscussionBoards_UpdateTopicSecured"
        ]
      },
      {
        "method": "POST",
        "route": "/api/modules/discussion-boards/topics/{topicRecordId:guid}/posts",
        "browserFunctions": [
          "postDiscussionReply"
        ],
        "parsers": [
          "parseDiscussionMutation"
        ],
        "procedures": [
          "sp_DiscussionBoards_PostReplySecured"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/modules/discussion-boards/posts/{recordId:guid}",
        "browserFunctions": [
          "updateDiscussionPost"
        ],
        "parsers": [
          "parseDiscussionMutation"
        ],
        "procedures": [
          "sp_DiscussionBoards_UpdatePostSecured"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/modules/discussion-boards/records/{recordId:guid}/favorite",
        "browserFunctions": [
          "setDiscussionFavorite"
        ],
        "parsers": [
          "parseDiscussionMutation"
        ],
        "procedures": [
          "sp_DiscussionBoards_SetFavoriteSecured"
        ]
      }
    ],
    "integrationNote": "Use the current typed client or the exact operations listed here."
  },
  {
    "slug": "mail-reader",
    "title": "Mail reader",
    "integrationKind": "page-module",
    "nativeComponentKey": "module.mail-reader",
    "apiBasePaths": [
      "/api/modules/mail-reader"
    ],
    "clientMethods": [],
    "operations": [
      {
        "method": "GET",
        "route": "/api/modules/mail-reader",
        "browserFunctions": [
          "listMailReaderMessages"
        ],
        "parsers": [
          "parseMailReaderList"
        ],
        "procedures": [
          "sp_MailReader_ListSecured"
        ]
      },
      {
        "method": "GET",
        "route": "/api/modules/mail-reader/{recordId:guid}",
        "browserFunctions": [
          "getMailReaderMessage"
        ],
        "parsers": [
          "parseMailReaderDetail"
        ],
        "procedures": [
          "sp_MailReader_GetSecured"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/modules/mail-reader/{recordId:guid}/read",
        "browserFunctions": [
          "setMailReaderRead"
        ],
        "parsers": [
          "parseMailReaderMutation"
        ],
        "procedures": [
          "sp_MailReader_SetReadSecured"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/modules/mail-reader/{recordId:guid}/favorite",
        "browserFunctions": [
          "setMailReaderFavorite"
        ],
        "parsers": [
          "parseMailReaderMutation"
        ],
        "procedures": [
          "sp_MailReader_SetFavoriteSecured"
        ]
      }
    ],
    "integrationNote": "Use the current typed client or the exact operations listed here."
  },
  {
    "slug": "favorites",
    "title": "Favorites",
    "integrationKind": "page-module",
    "nativeComponentKey": "module.favorites",
    "apiBasePaths": [
      "/api/modules/favorites"
    ],
    "clientMethods": [],
    "operations": [
      {
        "method": "GET",
        "route": "/api/modules/favorites",
        "browserFunctions": [
          "listFavorites"
        ],
        "parsers": [
          "parseFavoritesList"
        ],
        "procedures": [
          "sp_Favorites_ListSecured"
        ]
      },
      {
        "method": "GET",
        "route": "/api/modules/favorites/{recordId:guid}",
        "browserFunctions": [
          "getFavorite"
        ],
        "parsers": [
          "parseFavoriteDetail"
        ],
        "procedures": [
          "sp_Favorites_GetSecured"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/modules/favorites/{recordId:guid}/favorite",
        "browserFunctions": [
          "setFavorite"
        ],
        "parsers": [
          "parseFavoriteMutation"
        ],
        "procedures": [
          "sp_Favorites_SetSecured"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/modules/favorites/{recordId:guid}/preferences",
        "browserFunctions": [
          "updateFavoritePreferences"
        ],
        "parsers": [
          "parseFavoriteMutation"
        ],
        "procedures": [
          "sp_Favorites_UpdateSecured"
        ]
      }
    ],
    "integrationNote": "Use the current typed client or the exact operations listed here."
  },
  {
    "slug": "notifications",
    "title": "Notifications",
    "integrationKind": "page-module",
    "nativeComponentKey": "module.notifications",
    "apiBasePaths": [
      "/api/modules/notifications"
    ],
    "clientMethods": [],
    "operations": [
      {
        "method": "GET",
        "route": "/api/modules/notifications",
        "browserFunctions": [
          "listNotifications"
        ],
        "parsers": [
          "parseNotificationList"
        ],
        "procedures": [
          "sp_Notifications_ListSecured"
        ]
      },
      {
        "method": "GET",
        "route": "/api/modules/notifications/{notificationId:guid}",
        "browserFunctions": [
          "getNotification"
        ],
        "parsers": [
          "parseNotificationDetail"
        ],
        "procedures": [
          "sp_Notifications_GetSecured"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/modules/notifications/{notificationId:guid}/state",
        "browserFunctions": [
          "setNotificationState"
        ],
        "parsers": [
          "parseNotificationMutation"
        ],
        "procedures": [
          "sp_Notifications_SetStateSecured"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/modules/notifications/{notificationId:guid}/source-favorite",
        "browserFunctions": [
          "setNotificationSourceFavorite"
        ],
        "parsers": [
          "parseNotificationMutation"
        ],
        "procedures": [
          "sp_Notifications_SetSourceFavoriteSecured"
        ]
      }
    ],
    "integrationNote": "Use the current typed client or the exact operations listed here."
  },
  {
    "slug": "dynamic-records",
    "title": "Dynamic/custom records",
    "integrationKind": "page-module",
    "nativeComponentKey": "module.dynamic-records",
    "apiBasePaths": [
      "/api/modules/dynamic"
    ],
    "clientMethods": [],
    "operations": [
      {
        "method": "GET",
        "route": "/api/modules/dynamic/{moduleKey}/schema",
        "browserFunctions": [
          "getDynamicModuleSchema"
        ],
        "parsers": [
          "parseDynamicModuleSchema"
        ],
        "procedures": [
          "sp_DynamicModules_GetSchemaSecured"
        ]
      },
      {
        "method": "GET",
        "route": "/api/modules/dynamic/{moduleKey}",
        "browserFunctions": [
          "listDynamicModuleRecords"
        ],
        "parsers": [
          "parseDynamicModuleList"
        ],
        "procedures": [
          "sp_DynamicModules_ListSecured"
        ]
      },
      {
        "method": "GET",
        "route": "/api/modules/dynamic/{moduleKey}/{recordId:guid}",
        "browserFunctions": [
          "getDynamicModuleRecord"
        ],
        "parsers": [
          "parseDynamicModuleDetail"
        ],
        "procedures": [
          "sp_DynamicModules_GetSecured"
        ]
      },
      {
        "method": "POST",
        "route": "/api/modules/dynamic/{moduleKey}",
        "browserFunctions": [
          "createDynamicModuleRecord"
        ],
        "parsers": [
          "parseDynamicModuleMutation"
        ],
        "procedures": [
          "sp_DynamicModules_CreateSecured"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/modules/dynamic/{moduleKey}/{recordId:guid}",
        "browserFunctions": [
          "updateDynamicModuleRecord"
        ],
        "parsers": [
          "parseDynamicModuleMutation"
        ],
        "procedures": [
          "sp_DynamicModules_UpdateSecured"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/modules/dynamic/{moduleKey}/{recordId:guid}/favorite",
        "browserFunctions": [
          "setDynamicModuleFavorite"
        ],
        "parsers": [
          "parseDynamicModuleMutation"
        ],
        "procedures": [
          "sp_DynamicModules_SetFavoriteSecured"
        ]
      }
    ],
    "integrationNote": "Use the current typed client or the exact operations listed here."
  },
  {
    "slug": "active-workplace",
    "title": "ActiveWorkplace",
    "integrationKind": "page-module",
    "nativeComponentKey": "module.active-workplace",
    "apiBasePaths": [
      "/api/modules/active-workplace"
    ],
    "clientMethods": [],
    "operations": [
      {
        "method": "GET",
        "route": "/api/modules/active-workplace",
        "browserFunctions": [
          "listActiveWorkplaces"
        ],
        "parsers": [
          "parseActiveWorkplaceList"
        ],
        "procedures": [
          "sp_ActiveWorkplace_ListSecured"
        ]
      },
      {
        "method": "POST",
        "route": "/api/modules/active-workplace",
        "browserFunctions": [
          "createActiveWorkplace"
        ],
        "parsers": [
          "parseActiveWorkplaceMutation"
        ],
        "procedures": [
          "sp_ActiveWorkplace_CreateSecured"
        ]
      },
      {
        "method": "GET",
        "route": "/api/modules/active-workplace/{activeWorkplaceId:guid}",
        "browserFunctions": [
          "getActiveWorkplace"
        ],
        "parsers": [
          "parseActiveWorkplaceDetail"
        ],
        "procedures": [
          "sp_ActiveWorkplace_GetSecured"
        ]
      },
      {
        "method": "PATCH",
        "route": "/api/modules/active-workplace/{activeWorkplaceId:guid}",
        "browserFunctions": [
          "updateActiveWorkplace"
        ],
        "parsers": [
          "parseActiveWorkplaceMutation"
        ],
        "procedures": [
          "sp_ActiveWorkplace_UpdateSecured"
        ]
      },
      {
        "method": "POST",
        "route": "/api/modules/active-workplace/{activeWorkplaceId:guid}/status",
        "browserFunctions": [
          "setActiveWorkplaceStatus"
        ],
        "parsers": [
          "parseActiveWorkplaceMutation"
        ],
        "procedures": [
          "sp_ActiveWorkplace_SetStatusSecured"
        ]
      },
      {
        "method": "GET",
        "route": "/api/modules/active-workplace/{activeWorkplaceId:guid}/participants/catalog",
        "browserFunctions": [
          "getActiveWorkplaceParticipantCatalog"
        ],
        "parsers": [
          "parseActiveWorkplaceCatalog"
        ],
        "procedures": [
          "sp_ActiveWorkplace_GetParticipantCatalogSecured"
        ]
      },
      {
        "method": "POST",
        "route": "/api/modules/active-workplace/{activeWorkplaceId:guid}/participants",
        "browserFunctions": [
          "addActiveWorkplaceParticipant"
        ],
        "parsers": [
          "parseActiveWorkplaceMutation"
        ],
        "procedures": [
          "sp_ActiveWorkplace_AddParticipantSecured"
        ]
      },
      {
        "method": "DELETE",
        "route": "/api/modules/active-workplace/{activeWorkplaceId:guid}/participants/{activeWorkplaceParticipantId:guid}",
        "browserFunctions": [
          "removeActiveWorkplaceParticipant"
        ],
        "parsers": [
          "parseActiveWorkplaceMutation"
        ],
        "procedures": [
          "sp_ActiveWorkplace_RemoveParticipantSecured"
        ]
      },
      {
        "method": "POST",
        "route": "/api/modules/active-workplace/{activeWorkplaceId:guid}/activity",
        "browserFunctions": [
          "recordActiveWorkplaceActivity"
        ],
        "parsers": [
          "parseActiveWorkplaceMutation"
        ],
        "procedures": [
          "sp_ActiveWorkplace_RecordActivitySecured"
        ]
      },
      {
        "method": "POST",
        "route": "/api/modules/active-workplace/{activeWorkplaceId:guid}/graph/refresh",
        "browserFunctions": [
          "refreshActiveWorkplaceGraph"
        ],
        "parsers": [
          "parseActiveWorkplaceMutation"
        ],
        "procedures": [
          "sp_ActiveWorkplace_RefreshGraphSecured"
        ]
      },
      {
        "method": "GET",
        "route": "/api/modules/active-workplace/{activeWorkplaceId:guid}/playback",
        "browserFunctions": [
          "getActiveWorkplacePlayback"
        ],
        "parsers": [
          "parseActiveWorkplacePlayback"
        ],
        "procedures": [
          "sp_ActiveWorkplace_GetPlaybackSecured"
        ]
      }
    ],
    "integrationNote": "Use the current typed client or the exact operations listed here."
  },
  {
    "slug": "record-relations",
    "title": "Record relations",
    "integrationKind": "page-module",
    "nativeComponentKey": "module.record-graph",
    "apiBasePaths": [
      "/api/modules/record-graph"
    ],
    "clientMethods": [],
    "operations": [
      {
        "method": "GET",
        "route": "/api/modules/record-graph/records",
        "browserFunctions": [
          "searchRecordGraph"
        ],
        "parsers": [
          "parseRecordGraphSearch"
        ],
        "procedures": [
          "sp_RecordGraph_SearchSecured"
        ]
      },
      {
        "method": "GET",
        "route": "/api/modules/record-graph/{recordId:guid}",
        "browserFunctions": [
          "getRecordGraph"
        ],
        "parsers": [
          "parseRecordGraph"
        ],
        "procedures": [
          "sp_RecordGraph_GetSecured"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/modules/record-graph/{recordId:guid}/relations",
        "browserFunctions": [
          "addRecordGraphRelation"
        ],
        "parsers": [
          "parseRecordGraphMutation"
        ],
        "procedures": [
          "sp_RecordGraph_AddRelationSecured"
        ]
      },
      {
        "method": "DELETE",
        "route": "/api/modules/record-graph/relations/{recordRelationId:guid}",
        "browserFunctions": [
          "removeRecordGraphRelation"
        ],
        "parsers": [
          "parseRecordGraphMutation"
        ],
        "procedures": [
          "sp_RecordGraph_RemoveRelationSecured"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/modules/record-graph/{recordId:guid}/favorite",
        "browserFunctions": [
          "setRecordGraphFavorite"
        ],
        "parsers": [
          "parseFavoriteMutation"
        ],
        "procedures": [
          "sp_Favorites_SetSecured"
        ]
      },
      {
        "method": "GET",
        "route": "/api/modules/record-graph/{recordId:guid}/knowledge",
        "browserFunctions": [
          "getRelatedKnowledge"
        ],
        "parsers": [
          "parseRelatedKnowledge"
        ],
        "procedures": [
          "sp_kc_GetRelatedKnowledgeSecured"
        ]
      },
      {
        "method": "GET",
        "route": "/api/modules/record-graph/{recordId:guid}/knowledge/candidates",
        "browserFunctions": [
          "getContextualKnowledge"
        ],
        "parsers": [
          "parseContextualKnowledge"
        ],
        "procedures": [
          "sp_kc_GetContextualKnowledgeCandidatesSecured"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/modules/record-graph/{recordId:guid}/knowledge",
        "browserFunctions": [
          "linkKnowledgeToRecord"
        ],
        "parsers": [
          "parseKnowledgeRelationMutation"
        ],
        "procedures": [
          "sp_kc_LinkKnowledgeToRecord"
        ]
      },
      {
        "method": "DELETE",
        "route": "/api/modules/record-graph/knowledge-relations/{recordRelationId:guid}",
        "browserFunctions": [
          "unlinkKnowledgeFromRecord"
        ],
        "parsers": [
          "parseKnowledgeRelationMutation"
        ],
        "procedures": [
          "sp_kc_UnlinkKnowledgeFromRecord"
        ]
      }
    ],
    "integrationNote": "Use the current typed client or the exact operations listed here."
  },
  {
    "slug": "record-activity",
    "title": "Record activity",
    "integrationKind": "page-module",
    "nativeComponentKey": "module.record-activity",
    "apiBasePaths": [
      "/api/modules/record-activity"
    ],
    "clientMethods": [],
    "operations": [
      {
        "method": "GET",
        "route": "/api/modules/record-activity/records",
        "browserFunctions": [
          "searchRecordActivity"
        ],
        "parsers": [
          "parseRecordActivitySearch"
        ],
        "procedures": [
          "sp_RecordActivity_SearchSecured"
        ]
      },
      {
        "method": "GET",
        "route": "/api/modules/record-activity/{recordId:guid}",
        "browserFunctions": [
          "getRecordActivity"
        ],
        "parsers": [
          "parseRecordActivity"
        ],
        "procedures": [
          "sp_RecordActivity_GetSecured"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/modules/record-activity/{recordId:guid}/favorite",
        "browserFunctions": [
          "setRecordActivityFavorite"
        ],
        "parsers": [
          "parseFavoriteMutation"
        ],
        "procedures": [
          "sp_Favorites_SetSecured"
        ]
      }
    ],
    "integrationNote": "Use the current typed client or the exact operations listed here."
  },
  {
    "slug": "global-search",
    "title": "Global secured search",
    "integrationKind": "page-module",
    "nativeComponentKey": "module.global-search",
    "apiBasePaths": [
      "/api/modules/global-search"
    ],
    "clientMethods": [],
    "operations": [
      {
        "method": "GET",
        "route": "/api/modules/global-search",
        "browserFunctions": [
          "searchGlobalRecords"
        ],
        "parsers": [
          "parseGlobalSearch"
        ],
        "procedures": [
          "sp_GlobalSearch_SearchSecured"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/modules/global-search/records/{recordId:guid}/favorite",
        "browserFunctions": [
          "setGlobalSearchFavorite"
        ],
        "parsers": [
          "parseFavoriteMutation"
        ],
        "procedures": [
          "sp_Favorites_SetSecured"
        ]
      }
    ],
    "integrationNote": "Use the current typed client or the exact operations listed here."
  },
  {
    "slug": "api-modules-ai-insights-api",
    "title": "Ai Insights API",
    "integrationKind": "api-surface",
    "nativeComponentKey": "module.ai-insights",
    "apiBasePaths": [
      "/api/modules/ai-insights"
    ],
    "clientMethods": [],
    "operations": [
      {
        "method": "GET",
        "route": "/api/modules/ai-insights",
        "browserFunctions": [
          "listAiInsights"
        ],
        "parsers": [
          "parseAiInsightList"
        ],
        "procedures": [
          "sp_AiInsights_ListSecured"
        ]
      },
      {
        "method": "GET",
        "route": "/api/modules/ai-insights/{insightId:guid}",
        "browserFunctions": [
          "getAiInsight"
        ],
        "parsers": [
          "parseAiInsightDetail"
        ],
        "procedures": [
          "sp_AiInsights_GetSecured"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/modules/ai-insights/{insightId:guid}/state",
        "browserFunctions": [
          "setAiInsightState"
        ],
        "parsers": [
          "parseAiInsightState"
        ],
        "procedures": [
          "sp_AiInsights_SetStateSecured"
        ]
      }
    ],
    "integrationNote": "This API surface supports other first-class modules and has no standalone page renderer."
  },
  {
    "slug": "api-modules-payments-api",
    "title": "Payments Module API",
    "integrationKind": "api-surface",
    "nativeComponentKey": null,
    "apiBasePaths": [
      "/api/modules/payments"
    ],
    "clientMethods": [],
    "operations": [
      {
        "method": "GET",
        "route": "/api/modules/payments/settings",
        "browserFunctions": [
          "getTenantPaymentSettings"
        ],
        "parsers": [
          "parseTenantPaymentSettings"
        ],
        "procedures": [
          "sp_TenantPayments_GetSettingsSecured"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/modules/payments/settings/{moduleKey}",
        "browserFunctions": [
          "updateTenantPaymentPolicy"
        ],
        "parsers": [
          "parseTenantPaymentMutation"
        ],
        "procedures": [
          "sp_TenantPayments_UpdatePolicySecured"
        ]
      },
      {
        "method": "PUT",
        "route": "/api/modules/payments/connectors",
        "browserFunctions": [
          "upsertTenantPaymentConnector"
        ],
        "parsers": [
          "parseTenantPaymentMutation"
        ],
        "procedures": [
          "sp_TenantPayments_UpsertConnectorSecured"
        ]
      },
      {
        "method": "DELETE",
        "route": "/api/modules/payments/connectors/{connectorId:guid}",
        "browserFunctions": [
          "deactivateTenantPaymentConnector"
        ],
        "parsers": [
          "parseTenantPaymentMutation"
        ],
        "procedures": [
          "sp_TenantPayments_DeactivateConnectorSecured"
        ]
      },
      {
        "method": "GET",
        "route": "/api/modules/payments/methods",
        "browserFunctions": [],
        "parsers": [],
        "procedures": [
          "sp_TenantPayments_ListMethodsSecured"
        ]
      },
      {
        "method": "GET",
        "route": "/api/modules/payments/records/{recordId:guid}",
        "browserFunctions": [
          "getTenantRecordPayments"
        ],
        "parsers": [
          "parseTenantRecordPaymentSummary"
        ],
        "procedures": [
          "sp_TenantPayments_GetRecordSummarySecured"
        ]
      },
      {
        "method": "POST",
        "route": "/api/modules/payments/records/{recordId:guid}/charges",
        "browserFunctions": [
          "createTenantRecordCharge"
        ],
        "parsers": [
          "parseTenantPaymentMutation"
        ],
        "procedures": [
          "sp_TenantPayments_CreateChargeSecured"
        ]
      }
    ],
    "integrationNote": "This API surface supports other first-class modules and has no standalone page renderer."
  }
] as const satisfies readonly HeadlessCapabilityRecipe[];

9. Headless release checklist

  • Run a real login, refresh, reload, logout and expired-session journey; do not mock the transport in the only end-to-end test.
  • Probe every detail and mutation with an own ID, another tenant's real ID, and a random ID. Foreign/absent responses must not become an existence oracle.
  • Verify DataRole, Location, secure-field, AI-read and action permission changes take effect on the next request.
  • Assert list cardinality, stable ordering, first/middle/deep pagination, bounded payload size and no client-side “fetch everything then filter” path.
  • Exercise create/update/stale update/duplicate request, file failure, Workflow approval, ticket resolution, Inbox activity changes, rate limiting and restart recovery.
  • Keep correlation IDs through browser, API, SQL, workers and provider delivery; log safe codes, never tokens, secrets, SQL parameters or returned tenant data.
  • Test keyboard/screen-reader behavior, mobile layout, large photos, slow connections, 401/403/404/409/429/5xx states and abort/navigation races.

Use the native React catalog when the platform component already matches the experience, and the Developer Platform for external/server-to-server applications.