Integrations

Use the agent, webhook, and API auth hooks that sit on top of the shared client layer.

Agents

useAgentSession()

useAgentSession() is the entry hook for the agents surface. It resolves the current agent session, returns the actor and the available agents for that session, and optionally exchanges a ticket before it loads the session.

import { useAgentSession } from '@wacht/nextjs';export default function AgentShell({  ticket,}: {  ticket?: string | null;}) {  const {    hasSession,    sessionLoading,    sessionError,    actor,    agents,    ticketExchanged,  } = useAgentSession(ticket);  if (sessionLoading) {    return <div>Loading agent session...</div>;  }  if (!hasSession || sessionError) {    return <div>Access required</div>;  }  return (    <div>      <h1>{actor?.display_name ?? 'Actor'}</h1>      <p>{agents.length} agents available</p>      {ticket ? <p>Ticket exchanged: {String(ticketExchanged)}</p> : null}    </div>  );}
ticket?: string | null | undefined | undefined;
Optional session ticket. When present, the hook tries to exchange it once before it fetches the agent session.
hasSession?: boolean | undefined;
Whether the current user has a valid agent session.
sessionLoading?: boolean | undefined;
True while the ticket exchange or the session fetch is still in flight.
sessionError?: Error | null | undefined;
Transport or exchange failure. Missing-session responses are not exposed here.
sessionId?: string | null | undefined;
Session identifier from the loaded agent session.
actor?: Actor | null | undefined;
Current actor that owns the agent session.
id?: string | undefined;
Actor identifier.
subject_type?: string | undefined;
Actor subject type.
external_key?: string | undefined;
External actor key.
display_name?: string | undefined | undefined;
Display name for the actor when one is present.
deployment_id?: string | undefined | undefined;
Deployment identifier when attached to the actor.
agents?: Agent[] | undefined;
Agents available to the current session.
id?: string | undefined;
Agent identifier.
name?: string | undefined;
Human-readable agent name.
description?: string | undefined;
Optional agent description.
child_agents?: Agent[] | undefined | undefined;
Nested child agents when the deployment exposes them.
ticketExchanged?: boolean | undefined;
Whether the supplied ticket has already been exchanged successfully.
ticketLoading?: boolean | undefined;
Whether the hook is still exchanging the supplied ticket.
refetch?: () => Promise<void> | undefined;
Revalidates the loaded agent session.

useActorProjects()

useActorProjects() is the main project hook for the agents surface. It returns the current actor project list and the project-level mutations that create, update, archive, and unarchive those projects.

import { useActorProjects } from '@wacht/nextjs';export default function ProjectsPage() {  const { projects, loading, createProject } = useActorProjects();  if (loading) {    return <div>Loading projects...</div>;  }  return (    <div>      <button        onClick={async () => {          await createProject({            name: 'Planning',            agent_id: 'agent_123',          });        }}      >        Create project      </button>      <ul>        {projects.map((project) => (          <li key={project.id}>{project.name}</li>        ))}      </ul>    </div>  );}
options?: { includeArchived?: boolean; enabled?: boolean } | undefined | undefined;
Optional list controls.
includeArchived?: boolean | undefined | undefined;
Include archived projects in the returned list.
enabled?: boolean | undefined | undefined;
Disable the query entirely when the surrounding session is not ready.
projects?: ActorProject[] | undefined;
Projects for the current actor.
id?: string | undefined;
Project identifier.
name?: string | undefined;
Project name.
description?: string | undefined | undefined;
Optional project description.
status?: string | undefined;
Current project status.
coordinator_thread_id?: string | undefined | undefined;
Coordinator thread for the project when present.
review_thread_id?: string | undefined | undefined;
Review thread for the project when present.
updated_at?: string | undefined;
Last update timestamp.
archived_at?: string | undefined | undefined;
Archive timestamp when the project has been archived.
createProject?: (request: CreateActorProjectRequest) => Promise<ApiResult<ActorProject>> | undefined;
Creates a new project. The created project is available on `result.data`.
updateProject?: (projectId: string, request: UpdateActorProjectRequest) => Promise<ApiResult<ActorProject>> | undefined;
Updates one project and returns the updated project on `result.data`.
archiveProject?: (projectId: string) => Promise<ApiResult<ActorProject>> | undefined;
Archives one project and returns the archived project on `result.data`.
unarchiveProject?: (projectId: string) => Promise<ApiResult<ActorProject>> | undefined;
Restores one archived project and returns the project on `result.data`.

useActorProjectSearch()

useActorProjectSearch() is the search-focused project hook. It returns paged project search results for a free-text query and is a better fit for palettes, jump menus, and search boxes than the full project list hook.

import { useState } from 'react';import { useActorProjectSearch } from '@wacht/nextjs';export default function ProjectSearch() {  const [query, setQuery] = useState('');  const { projects, loading } = useActorProjectSearch({ query, limit: 12 });  return (    <div>      <input value={query} onChange={(event) => setQuery(event.target.value)} />      {loading ? <div>Searching…</div> : null}      <ul>        {projects.map((project) => (          <li key={project.id}>{project.name}</li>        ))}      </ul>    </div>  );}
projects?: ActorProject[] | undefined;
Current page of project matches.
loading?: boolean | undefined;
Whether the current search request is still loading.
hasMore?: boolean | undefined;
Whether the backend has more search results beyond this page.
nextCursor?: string | undefined | undefined;
Cursor for the next page when the backend returned one.

useActorThreadSearch()

useActorThreadSearch() is the search hook for the actor-wide thread surface. It returns matching threads across projects, which makes it useful for jump menus, global search palettes, and “open thread” UIs.

import { useState } from 'react';import { useActorThreadSearch } from '@wacht/nextjs';export default function ThreadSearch() {  const [query, setQuery] = useState('');  const { threads } = useActorThreadSearch({ query, limit: 16 });  return (    <div>      <input value={query} onChange={(event) => setQuery(event.target.value)} />      <ul>        {threads.map((thread) => (          <li key={thread.id}>{thread.title || thread.responsibility || thread.id}</li>        ))}      </ul>    </div>  );}
threads?: AgentThread[] | undefined;
Current page of matching threads.
hasMore?: boolean | undefined;
Whether more thread search results are available.
nextCursor?: string | undefined | undefined;
Cursor for a later page when the backend returned one.

useProjectThreads()

useProjectThreads() is the project-local thread collection hook. It lists the threads that belong to one project and exposes the thread mutations that create, update, archive, and unarchive those threads.

import { useProjectThreads } from '@wacht/nextjs';export default function ProjectThreadList({  projectId,}: {  projectId: string;}) {  const { threads, createThread } = useProjectThreads(projectId);  return (    <div>      <button        onClick={async () => {          await createThread({            title: 'Planning thread',            agent_id: 'agent_123',          });        }}      >        New thread      </button>      <ul>        {threads.map((thread) => (          <li key={thread.id}>{thread.title}</li>        ))}      </ul>    </div>  );}
threads?: AgentThread[] | undefined;
Threads in the current project.
createThread?: (request: CreateAgentThreadRequest) => Promise<ApiResult<AgentThread>> | undefined;
Creates a thread in the current `projectId`. The created thread is available on `result.data`.
createThreadForProject?: (targetProjectId: string, request: CreateAgentThreadRequest) => Promise<ApiResult<AgentThread>> | undefined;
Creates a thread for an explicit target project and is useful when the surrounding UI can switch project targets.
updateThread?: (threadId: string, request: UpdateAgentThreadRequest) => Promise<ApiResult<AgentThread>> | undefined;
Updates a thread and returns the updated thread on `result.data`.
archiveThread?: (threadId: string) => Promise<ApiResult<AgentThread>> | undefined;
Archives one thread and returns the archived thread on `result.data`.
unarchiveThread?: (threadId: string) => Promise<ApiResult<AgentThread>> | undefined;
Restores one thread and returns the thread on `result.data`.

useProjectThreadFeed()

useProjectThreadFeed() is the infinite-list thread feed hook. It returns a flattened thread list together with loadMore() and the archive/query controls that a project sidebar usually needs.

import { useProjectThreadFeed } from '@wacht/nextjs';export default function ThreadFeed({  projectId,}: {  projectId: string;}) {  const { threads, hasMore, loadMore } = useProjectThreadFeed(projectId, {    query: '',  });  return (    <div>      <ul>        {threads.map((thread) => (          <li key={thread.id}>{thread.title}</li>        ))}      </ul>      {hasMore ? <button onClick={() => void loadMore()}>Load more</button> : null}    </div>  );}
threads?: AgentThread[] | undefined;
Flattened thread feed across the currently loaded pages.
hasMore?: boolean | undefined;
Whether another page can be loaded.
loadingMore?: boolean | undefined;
Whether the next page is currently loading.
loadMore?: () => Promise<void> | undefined;
Loads the next page when `hasMore` is true.

useAgentThread()

useAgentThread() is the single-thread hook. It loads one thread by id and exposes the thread-level update, archive, and unarchive helpers for detail pages and editors.

import { useAgentThread } from '@wacht/nextjs';export default function ThreadDetail({  threadId,}: {  threadId: string;}) {  const { thread, updateThread } = useAgentThread(threadId, true);  if (!thread) {    return <div>Loading thread...</div>;  }  return (    <button      onClick={async () => {        await updateThread({          title: 'Updated title',        });      }}    >      {thread.title}    </button>  );}
thread?: AgentThread | null | undefined;
The loaded thread record.
id?: string | undefined;
Thread identifier.
project_id?: string | undefined;
Owning project identifier.
title?: string | undefined;
Thread title.
thread_purpose?: string | undefined;
Thread purpose such as conversation or review.
status?: string | undefined;
Current execution state.
execution_state?: ThreadExecutionState | undefined | undefined;
Execution-specific state such as pending approvals.

useAgentThreadConversation()

useAgentThreadConversation() is the live conversation hook behind the agent chat surface. It loads message history, subscribes to streaming updates, tracks pending submissions and approvals, and exposes the send, approval, and execution controls that the chat UI needs.

import { useAgentThreadConversation } from '@wacht/nextjs';export default function ThreadConversation({  threadId,}: {  threadId: string;}) {  const {    messages,    sendMessage,    pendingApprovalRequest,    submitApprovalResponse,  } = useAgentThreadConversation({ threadId });  return (    <div>      <ul>        {messages.map((message) => (          <li key={message.id}>{message.content.type}</li>        ))}      </ul>      {pendingApprovalRequest ? (        <button          onClick={() =>            submitApprovalResponse('allow_once', pendingApprovalRequest.request_message_id)          }        >          Approve once        </button>      ) : null}      <button onClick={() => void sendMessage('Continue with the plan')}>Send</button>    </div>  );}
messages?: ConversationMessage[] | undefined;
Conversation history for the thread, kept sorted by timestamp.
pendingMessage?: string | null | undefined;
Optimistic outgoing message text while a send is still in progress.
pendingFiles?: File[] | null | undefined;
Optimistic outgoing file attachments while a send is still in progress.
messagesLoading?: boolean | undefined;
Whether the initial message history is still loading.
hasMoreMessages?: boolean | undefined;
Whether older history can still be loaded.
isLoadingMore?: boolean | undefined;
Whether older history is currently loading.
sendMessage?: (message: string, files?: File[]) => Promise<void> | undefined;
Sends a new user message and optional file attachments into the thread.
loadMoreMessages?: () => Promise<void> | undefined;
Loads older conversation history.
submitApprovalResponse?: (mode: 'allow_once' | 'allow_always' | 'reject', requestMessageId?: string) => Promise<void> | undefined;
Responds to the current approval request.
cancelExecution?: () => Promise<void> | undefined;
Cancels the current execution when the thread is running.
pendingApprovalRequest?: ThreadPendingApprovalRequestState | null | undefined;
Current approval request derived from the live execution state when one exists.
activeApprovalRequestId?: string | null | undefined;
Message id for the current approval request.
hasActiveRun?: boolean | undefined;
Whether the thread is currently in an active run state.
isRunning?: boolean | undefined;
Whether the execution state is currently running.

useAgentThreadFilesystem()

useAgentThreadFilesystem() is the thread workspace file hook. It exposes the top-level listing for the thread filesystem and the helper methods that read individual files or nested directories inside that workspace.

import { useEffect } from 'react';import { useAgentThreadFilesystem } from '@wacht/nextjs';export default function FilesystemPane({  threadId,}: {  threadId: string;}) {  const { filesystem, getFile } = useAgentThreadFilesystem(threadId, true);  useEffect(() => {    const firstFile = filesystem.files.find((entry) => !entry.is_dir);    if (firstFile) {      void getFile(firstFile.path);    }  }, [filesystem.files, getFile]);  return <div>{filesystem.files.length} items</div>;}
filesystem?: ProjectTaskWorkspaceListing | undefined;
Current top-level filesystem listing.
exists?: boolean | undefined;
Whether the workspace exists at all.
files?: ProjectTaskWorkspaceFileEntry[] | undefined;
Current entries in the listing.
getFile?: (path: string) => Promise<ProjectTaskWorkspaceFileContent & { blob: Blob }> | undefined;
Loads one file from the thread workspace and returns file metadata plus a `Blob`.
listDirectory?: (path?: string) => Promise<ProjectTaskWorkspaceListing> | undefined;
Reads a nested directory listing without replacing the hook API contract.

useAgentThreadEvents()

useAgentThreadEvents() reads the paged event feed for one thread. It is the right hook for activity timelines, execution logs, and review surfaces that need the thread event stream but not the full conversation surface.

import { useAgentThreadEvents } from '@wacht/nextjs';export default function ThreadEvents({  threadId,}: {  threadId: string;}) {  const { events, hasMore, loadMore } = useAgentThreadEvents(threadId, {    enabled: !!threadId,  });  return (    <div>      <ul>        {events.map((event) => (          <li key={event.id}>{event.event_type}</li>        ))}      </ul>      {hasMore ? <button onClick={() => void loadMore()}>More</button> : null}    </div>  );}
events?: ThreadEvent[] | undefined;
Flattened event list for the current thread.
hasMore?: boolean | undefined;
Whether more event pages are available.
loadingMore?: boolean | undefined;
Whether the next event page is currently loading.

useAgentThreadAssignments()

useAgentThreadAssignments() reads the assignment feed for one thread. It is useful for coordinator and review surfaces where you need the ordered assignment list without the larger task board item surface.

import { useAgentThreadAssignments } from '@wacht/nextjs';export default function ThreadAssignments({  threadId,}: {  threadId: string;}) {  const { assignments } = useAgentThreadAssignments(threadId, {    enabled: !!threadId,  });  return (    <ul>      {assignments.map((assignment) => (        <li key={assignment.id}>{assignment.assignment_role}</li>      ))}    </ul>  );}
assignments?: ProjectTaskBoardItemAssignment[] | undefined;
Flattened assignment list for the thread.
id?: string | undefined;
Assignment identifier.
assignment_role?: string | undefined;
Role this assignment plays in the task flow.
assignment_order?: number | undefined;
Execution order for the assignment.
status?: string | undefined;
Current assignment status.
result_status?: string | undefined | undefined;
Outcome status when the assignment has completed.

useProjectTasks()

useProjectTasks() is the project task board hook. It returns the current task items for one project and exposes the task-level create, archive, and unarchive helpers used by task board screens.

import { useProjectTasks } from '@wacht/nextjs';export default function ProjectTasks({  projectId,}: {  projectId: string;}) {  const { tasks, createTask } = useProjectTasks(projectId, true, {    limit: 40,  });  return (    <div>      <button        onClick={async () => {          await createTask({            title: 'Review webhook errors',            priority: 'high',          });        }}      >        New task      </button>      <ul>        {tasks.map((task) => (          <li key={task.id}>{task.title}</li>        ))}      </ul>    </div>  );}
tasks?: ProjectTaskBoardItem[] | undefined;
Flattened task items for the current filter.
createTask?: (request: CreateProjectTaskBoardItemRequest, files?: File[]) => Promise<ApiResult<ProjectTaskBoardItem>> | undefined;
Creates a task board item and returns the created item on `result.data`.
archiveTask?: (itemId: string) => Promise<ApiResult<ProjectTaskBoardItem>> | undefined;
Archives one task item and returns the archived item on `result.data`.
unarchiveTask?: (itemId: string) => Promise<ApiResult<ProjectTaskBoardItem>> | undefined;
Restores one task item and returns the restored item on `result.data`.

useProjectTaskBoardItem()

useProjectTaskBoardItem() is the detail hook for one task board item. It combines the item record, journal events, assignments, and workspace listing so a task detail screen can stay on one hook instead of composing those pieces manually.

import { useProjectTaskBoardItem } from '@wacht/nextjs';export default function TaskDetail({  projectId,  itemId,}: {  projectId: string;  itemId: string;}) {  const { item, appendJournal, taskWorkspace } = useProjectTaskBoardItem(    projectId,    itemId,    true,  );  return (    <div>      <h1>{item?.title}</h1>      <p>{taskWorkspace.files.length} workspace entries</p>      <button        onClick={async () => {          await appendJournal({            summary: 'Reviewed task output',          });        }}      >        Add journal entry      </button>    </div>  );}
item?: ProjectTaskBoardItem | null | undefined;
The task board item itself.
events?: ProjectTaskBoardItemEvent[] | undefined;
Flattened task journal and event feed.
assignments?: ProjectTaskBoardItemAssignment[] | undefined;
Flattened assignment list for the task.
taskWorkspace?: ProjectTaskWorkspaceListing | undefined;
Current task workspace listing.
updateItem?: (request: UpdateProjectTaskBoardItemRequest, files?: File[]) => Promise<ApiResult<ProjectTaskBoardItem>> | undefined;
Updates the item and returns the updated item on `result.data`.
appendJournal?: (request: AppendProjectTaskBoardItemJournalRequest, files?: File[]) => Promise<ApiResult<ProjectTaskBoardItemEvent>> | undefined;
Appends a journal entry and returns the new event on `result.data`.
getTaskWorkspaceFile?: (path: string) => Promise<ApiResult<ProjectTaskWorkspaceFileContent>> | undefined;
Reads one workspace file. The file payload is available on `result.data`.

useAgentThreadTaskGraphs()

useAgentThreadTaskGraphs() reads the paged task graph bundles for one thread. It is the hook behind task graph drawers and graph timelines, where the UI needs the graph, nodes, edges, and summary together.

import { useAgentThreadTaskGraphs } from '@wacht/nextjs';export default function TaskGraphs({  threadId,}: {  threadId: string;}) {  const { graphs, latestGraph } = useAgentThreadTaskGraphs(threadId, true);  return (    <div>      <p>{graphs.length} graphs loaded</p>      <p>Latest: {latestGraph?.graph.status ?? 'none'}</p>    </div>  );}
graphs?: ThreadTaskGraphBundle[] | undefined;
Loaded task graph bundles for the thread.
graph?: ThreadTaskGraph | undefined;
Graph metadata.
nodes?: ThreadTaskNode[] | undefined;
Nodes in the graph.
edges?: ThreadTaskEdge[] | undefined;
Edges between nodes.
summary?: ThreadTaskGraphSummary | null | undefined | undefined;
Optional computed summary for the graph.
latestGraph?: ThreadTaskGraphBundle | null | undefined;
Convenience handle for the first loaded graph bundle.

useActorMcpServers()

useActorMcpServers() is the MCP server management hook for the agents surface. It lists the deployment MCP servers available to the current actor and exposes the two connection actions that open or revoke a user connection.

import { useActorMcpServers } from '@wacht/nextjs';export default function McpServers() {  const { servers, connect, disconnect } = useActorMcpServers(true);  return (    <ul>      {servers.map((server) => (        <li key={server.id}>          {server.name}          <button            onClick={async () => {              const result = await connect(server.id);              window.open(result.data.auth_url, '_blank', 'noopener,noreferrer');            }}          >            Connect          </button>          <button onClick={() => void disconnect(server.id)}>Disconnect</button>        </li>      ))}    </ul>  );}
servers?: ActorMcpServerSummary[] | undefined;
Current MCP servers available to the actor.
id?: string | undefined;
MCP server identifier.
name?: string | undefined;
Display name.
endpoint?: string | undefined;
Configured server endpoint.
auth_type?: string | undefined;
Authentication strategy for the server.
requires_user_connection?: boolean | undefined;
Whether the current actor must connect the server before it can be used.
connection_status?: "ready" | "connected" | "not_connected" | "expired" | undefined;
Current user connection status.
connected_at?: string | undefined | undefined;
Connection timestamp when the user has connected the server.
expires_at?: string | undefined | undefined;
Expiry timestamp for an expiring connection.
connect?: (mcpServerId: string) => Promise<ApiResult<{ auth_url: string }>> | undefined;
Starts the user connection flow and returns the authorization URL on `result.data.auth_url`.
disconnect?: (mcpServerId: string) => Promise<ApiResult<{ success: boolean }>> | undefined;
Disconnects the current actor from the server and returns the success payload on `result.data`.

Webhooks

useWebhookAppSession()

useWebhookAppSession() is the entry hook for the webhook console. It resolves the current webhook app session, exposes the current webhook app, and bundles the top-level endpoint, settings, replay, and secret-rotation actions that the rest of your webhook UI can share.

import { useWebhookAppSession } from '@wacht/nextjs';export default function WebhookShell({  ticket,}: {  ticket?: string | null;}) {  const {    hasSession,    sessionLoading,    webhookApp,    rotateSecret,  } = useWebhookAppSession(ticket);  if (sessionLoading) {    return <div>Loading webhook app...</div>;  }  if (!hasSession) {    return <div>Access required</div>;  }  return (    <div>      <h1>{webhookApp?.name}</h1>      <button onClick={rotateSecret}>Rotate secret</button>    </div>  );}
ticket?: string | null | undefined | undefined;
Optional session ticket for the webhook console.
hasSession?: boolean | undefined;
Whether the current user has a valid webhook app session.
sessionLoading?: boolean | undefined;
True while the ticket exchange or session fetch is still in progress.
sessionError?: Error | null | undefined;
Non-session transport or exchange failure.
sessionId?: string | null | undefined;
Current webhook session identifier.
webhookApp?: WebhookAppInfo | null | undefined;
Current webhook app metadata.
app_slug?: string | undefined;
Webhook app slug.
name?: string | undefined;
Webhook app name.
signing_secret?: string | undefined;
Current webhook signing secret.
is_active?: boolean | undefined;
Whether the webhook app is active.
failure_notification_emails?: string[] | undefined | undefined;
Emails that receive webhook failure notifications.
ticketExchanged?: boolean | undefined;
Whether the supplied ticket has already been exchanged successfully.
ticketLoading?: boolean | undefined;
Whether the ticket exchange is still running.
refetch?: () => Promise<void> | undefined;
Revalidates the current webhook app session.
createEndpoint?: (options: CreateEndpointOptions) => Promise<ApiResult<EndpointWithSubscriptions>> | undefined;
Creates a webhook endpoint for the current app. The created endpoint is available on `result.data`.
updateEndpoint?: (endpointId: string, options: UpdateEndpointOptions) => Promise<ApiResult<EndpointWithSubscriptions>> | undefined;
Updates an existing endpoint. The updated endpoint is available on `result.data`.
deleteEndpoint?: (endpointId: string) => Promise<ApiResult<DeleteEndpointResponse>> | undefined;
Deletes an endpoint. The delete result is available on `result.data`.
testEndpoint?: (endpointId: string, options: TestEndpointOptions) => Promise<ApiResult<TestEndpointResponse>> | undefined;
Sends a test delivery to an endpoint. The test result is available on `result.data`.
rotateSecret?: () => Promise<ApiResult<WebhookAppInfo>> | undefined;
Rotates the webhook signing secret. The updated app payload is available on `result.data`.
updateSettings?: (options: UpdateWebhookSettingsOptions) => Promise<ApiResult<WebhookSettingsResponse>> | undefined;
Updates webhook app settings such as failure notification emails. The updated settings are available on `result.data`.
replayDelivery?: (options: ReplayWebhookDeliveryOptions) => Promise<ApiResult<ReplayWebhookDeliveryResponse>> | undefined;
Starts a delivery replay job. The queued task information is available on `result.data`.
fetchReplayTaskStatus?: (options: ReplayTaskStatusOptions) => Promise<ApiResult<ReplayTaskStatusResponse>> | undefined;
Reads the status of one replay job. The task state is available on `result.data`.
fetchReplayTasks?: (options?: ReplayTaskListOptions) => Promise<ApiResult<ReplayTaskListResponse>> | undefined;
Lists replay jobs. The page payload is available on `result.data`.
cancelReplayTask?: (options: CancelReplayTaskOptions) => Promise<ApiResult<CancelReplayTaskResponse>> | undefined;
Cancels a replay job. The cancellation result is available on `result.data`.
fetchDeliveryDetail?: (deliveryId: string) => Promise<ApiResult<WebhookDeliveryDetail[]>> | undefined;
Fetches detailed delivery attempts for one delivery. The attempt list is available on `result.data`.

useWebhookStats()

useWebhookStats() is the small summary hook for the webhook surface. It returns the top-level counts for endpoints, events, and pending deliveries, which makes it a good fit for dashboard cards, header metrics, and other compact overview UI.

import { useWebhookStats } from '@wacht/nextjs';export default function WebhookSnapshot() {  const { stats, loading } = useWebhookStats();  if (loading) {    return <div>Loading stats...</div>;  }  return (    <div>      <p>Endpoints: {stats?.endpoint_count ?? 0}</p>      <p>Events: {stats?.event_count ?? 0}</p>      <p>Pending deliveries: {stats?.pending_deliveries ?? 0}</p>    </div>  );}
stats?: WebhookStats | null | undefined;
Top-level webhook counters.
endpoint_count?: number | undefined;
Number of configured webhook endpoints.
event_count?: number | undefined;
Number of known webhook events.
pending_deliveries?: number | undefined;
Number of deliveries that are still pending.
loading?: boolean | undefined;
Whether the stats query is still loading.
error?: unknown | undefined;
SWR error for the stats query.
refetch?: () => void | undefined;
Revalidates the webhook stats query.

useWebhookEndpoints()

useWebhookEndpoints() is the main list hook for the webhook endpoints surface. It returns the current endpoint list with subscriptions attached, which makes it the natural source for endpoint tables, endpoint pickers, and navigation into endpoint detail pages.

import { useWebhookEndpoints } from '@wacht/nextjs';export default function EndpointList() {  const { endpoints, loading } = useWebhookEndpoints();  if (loading) {    return <div>Loading endpoints...</div>;  }  return (    <ul>      {endpoints.map((endpoint) => (        <li key={endpoint.id}>          {endpoint.url} · {endpoint.subscribed_events.length} events        </li>      ))}    </ul>  );}
endpoints?: EndpointWithSubscriptions[] | undefined;
Webhook endpoints for the current app.
id?: string | undefined;
Endpoint identifier.
deployment_id?: string | undefined;
Deployment that owns the endpoint.
app_slug?: string | undefined;
Webhook app slug.
url?: string | undefined;
Delivery URL for the endpoint.
description?: string | undefined | undefined;
Optional endpoint description.
headers?: Record<string, string> | undefined | undefined;
Static headers sent with deliveries.
is_active?: boolean | undefined;
Whether the endpoint is active.
max_retries?: number | undefined;
Maximum retry count for deliveries.
timeout_seconds?: number | undefined;
Delivery timeout in seconds.
failure_count?: number | undefined;
Observed failure count for the endpoint.
last_failure_at?: string | undefined | undefined;
Timestamp of the last failure when one exists.
auto_disabled?: boolean | undefined;
Whether the endpoint has been auto-disabled.
auto_disabled_at?: string | undefined | undefined;
Timestamp when the endpoint was auto-disabled.
rate_limit_config?: RateLimitConfig | null | undefined | undefined;
Optional per-endpoint rate limit configuration.
duration_ms?: number | undefined;
Rate-limit window size in milliseconds.
max_requests?: number | undefined;
Maximum requests allowed in that window.
created_at?: string | undefined;
Creation timestamp.
updated_at?: string | undefined;
Last update timestamp.
subscribed_events?: string[] | undefined;
List of event names this endpoint subscribes to.
subscriptions?: WebhookEventSubscription[] | undefined;
Expanded event subscription records.
event_name?: string | undefined;
Subscribed event name.
filter_rules?: Record<string, unknown> | undefined | undefined;
Optional filter rules for that event subscription.
loading?: boolean | undefined;
Whether the endpoint list is still loading.
error?: unknown | undefined;
SWR error for the endpoint query.
refetch?: () => void | undefined;
Revalidates the endpoint list.

useCreateWebhookEndpoint()

useCreateWebhookEndpoint() is the narrow write hook for creating a webhook endpoint. It is useful when your screen only needs endpoint creation and does not need the broader webhook app session helpers from useWebhookAppSession().

import { useCreateWebhookEndpoint } from '@wacht/nextjs';export default function CreateEndpointButton() {  const { createEndpoint } = useCreateWebhookEndpoint();  async function handleCreate() {    await createEndpoint({      url: 'https://example.com/webhooks',      subscribed_events: ['user.created'],    });  }  return <button onClick={handleCreate}>Create endpoint</button>;}
createEndpoint?: (options: CreateEndpointOptions) => Promise<ApiResult<EndpointWithSubscriptions>> | undefined;
Creates one webhook endpoint. The created endpoint is available on `result.data`.
options.url?: string | undefined;
Destination URL for the webhook endpoint.
options.description?: string | undefined | undefined;
Optional human-readable endpoint description.
options.subscribed_events?: string[] | undefined;
List of event names that should be delivered to the endpoint.
options.subscriptions?: WebhookEventSubscription[] | undefined | undefined;
Expanded event subscriptions, including optional filter rules.
event_name?: string | undefined;
Subscribed event name.
filter_rules?: Record<string, unknown> | undefined | undefined;
Optional filter rules for that event.
options.headers?: Record<string, string> | undefined | undefined;
Static headers sent with each webhook delivery.
options.rate_limit_config?: RateLimitConfig | null | undefined | undefined;
Optional per-endpoint rate limit configuration.
duration_ms?: number | undefined;
Rate-limit window size in milliseconds.
max_requests?: number | undefined;
Maximum requests allowed in that window.
loading?: boolean | undefined;
Current implementation always returns `false` for this hook.
error?: unknown | undefined;
Current implementation always returns `null` for this hook.

useWebhookDeliveries()

useWebhookDeliveries() is the main operational list hook for webhook traffic. It returns delivery rows for the current app, with optional filters for endpoint, event, status, and cursor position, which makes it the hook you use for webhook logs, endpoint delivery views, and replay selection surfaces.

import { useState } from 'react';import { useWebhookDeliveries } from '@wacht/nextjs';export default function WebhookLogsPage() {  const [status, setStatus] = useState<string>('all');  const [eventName, setEventName] = useState<string>('all');  const { deliveries, has_more, next_cursor, loading } = useWebhookDeliveries({    status: status === 'all' ? undefined : status,    event_name: eventName === 'all' ? undefined : eventName,    limit: 30,  });  if (loading) {    return <div>Loading deliveries...</div>;  }  return (    <div>      <p>{deliveries.length} deliveries</p>      <p>{has_more ? next_cursor : 'No more pages'}</p>    </div>  );}
options?: UseWebhookDeliveriesOptions | undefined | undefined;
Optional delivery list filters.
endpoint_id?: string | undefined | undefined;
Restricts the list to one webhook endpoint.
status?: string | undefined | undefined;
Restricts the list to one delivery status such as success, failed, or filtered.
event_name?: string | undefined | undefined;
Restricts the list to one event name.
limit?: number | undefined | undefined;
Maximum number of deliveries to load in one page.
cursor?: string | undefined | undefined;
Opaque cursor for the next page of deliveries.
deliveries?: WebhookDelivery[] | undefined;
Current page of delivery rows.
id?: string | undefined;
Delivery identifier.
deployment_id?: string | undefined;
Deployment that owns the delivery.
app_slug?: string | undefined;
Webhook app slug.
endpoint_id?: string | undefined;
Endpoint that received the delivery.
event_name?: string | undefined;
Event name that produced the delivery.
event_type?: string | undefined;
Event type label for the delivery.
status?: string | undefined;
Current delivery status.
http_status_code?: number | undefined | undefined;
HTTP status returned by the destination when available.
response_status?: number | undefined | undefined;
Normalized response status when one is recorded.
response_time_ms?: number | undefined | undefined;
Measured response time in milliseconds when available.
attempt_number?: number | undefined;
Current attempt number for the delivery.
max_attempts?: number | undefined;
Maximum number of retry attempts allowed for the delivery.
timestamp?: string | undefined;
Primary delivery timestamp.
created_at?: string | undefined;
Creation timestamp for the delivery record.
has_more?: boolean | undefined;
Whether another page of deliveries is available.
next_cursor?: string | undefined | undefined;
Cursor token for the next delivery page.
loading?: boolean | undefined;
Whether the current delivery query is still loading.
error?: unknown | undefined;
SWR error for the delivery query.
refetch?: () => void | undefined;
Revalidates the current delivery page.

useWebhookEvents()

useWebhookEvents() returns the event catalog for the current webhook app. It is the hook you use when you want to show the available event names, descriptions, schema metadata, or example payloads in your own webhook console.

import { useWebhookEvents } from '@wacht/nextjs';export default function EventCatalog() {  const { events, loading } = useWebhookEvents();  if (loading) {    return <div>Loading events...</div>;  }  return (    <ul>      {events.map((event) => (        <li key={event.event_name}>          {event.event_name}        </li>      ))}    </ul>  );}
events?: WebhookAppEvent[] | undefined;
Webhook event catalog entries.
deployment_id?: string | undefined;
Deployment that owns the event definition.
app_slug?: string | undefined;
Webhook app slug.
event_name?: string | undefined;
Canonical event name.
group?: string | undefined | undefined;
Optional grouping label for catalog UI.
description?: string | undefined | undefined;
Human-readable event description.
schema?: Record<string, unknown> | undefined | undefined;
Optional event schema object.
example_payload?: Record<string, unknown> | undefined | undefined;
Optional example payload for the event.
is_archived?: boolean | undefined;
Whether the event has been archived.
created_at?: string | undefined;
Creation timestamp for the event definition.
loading?: boolean | undefined;
Whether the event catalog is still loading.
error?: unknown | undefined;
SWR error for the event catalog query.
refetch?: () => void | undefined;
Revalidates the event catalog.

useWebhookAnalytics()

useWebhookAnalytics() returns aggregate webhook metrics for a selected time window. It is the hook you use for overview cards, operational summaries, and endpoint-level performance snapshots where you need rolled-up counts and latency metrics instead of raw delivery rows.

import { useWebhookAnalytics } from '@wacht/nextjs';export default function WebhookOverview() {  const { analytics, loading } = useWebhookAnalytics({    fields: ['total_deliveries', 'successful', 'failed', 'success_rate'],  });  if (loading) {    return <div>Loading analytics...</div>;  }  return (    <div>      <p>Total deliveries: {analytics?.total_deliveries ?? 0}</p>      <p>Success rate: {(analytics?.success_rate ?? 0).toFixed(1)}%</p>    </div>  );}
options?: UseWebhookAnalyticsOptions | undefined | undefined;
Optional analytics query settings.
start_date?: string | undefined | undefined;
Inclusive start timestamp for the analytics window.
end_date?: string | undefined | undefined;
Inclusive end timestamp for the analytics window.
endpoint_id?: string | undefined | undefined;
Restricts the analytics query to one webhook endpoint.
fields?: string[] | undefined | undefined;
List of aggregate fields the backend should compute.
analytics?: WebhookAnalyticsResponse | null | undefined;
Aggregate analytics payload.
total_deliveries?: number | undefined;
Total deliveries in the selected range when that path is requested.
total_events?: number | undefined;
Distinct delivery count used as the current total-events metric.
successful?: number | undefined;
Number of successful deliveries.
failed?: number | undefined;
Number of failed or permanently failed deliveries.
filtered?: number | undefined;
Number of filtered deliveries.
success_rate?: number | undefined;
Success rate for the selected time window.
avg_response_time_ms?: number | undefined | undefined;
Average response time in milliseconds.
p50_response_time_ms?: number | undefined | undefined;
Median response time in milliseconds.
p95_response_time_ms?: number | undefined | undefined;
95th percentile response time in milliseconds.
p99_response_time_ms?: number | undefined | undefined;
99th percentile response time in milliseconds.
avg_payload_size?: number | undefined | undefined;
Average payload size in bytes.
loading?: boolean | undefined;
Whether the analytics query is still loading.
error?: unknown | undefined;
SWR error for the analytics query.
refetch?: () => void | undefined;
Revalidates the analytics query.

useWebhookTimeseries()

useWebhookTimeseries() returns bucketed delivery metrics for a selected time range. It is the hook you use for webhook charts, trend views, and endpoint-level time-based dashboards where the UI needs counts grouped by hour or day rather than one aggregate snapshot.

import { useWebhookTimeseries } from '@wacht/nextjs';export default function DeliveryTrend({  startDate,  endDate,}: {  startDate: string;  endDate: string;}) {  const { timeseries, loading } = useWebhookTimeseries({    start_date: startDate,    end_date: endDate,    interval: 'day',  });  if (loading) {    return <div>Loading chart data...</div>;  }  return <div>{timeseries.length} points</div>;}
options?: UseWebhookTimeseriesOptions | undefined | undefined;
Optional timeseries query settings.
start_date?: string | undefined | undefined;
Inclusive start timestamp for the chart range.
end_date?: string | undefined | undefined;
Inclusive end timestamp for the chart range.
interval?: string | undefined | undefined;
Requested time bucket size, such as `hour` or `day`.
endpoint_id?: string | undefined | undefined;
Restricts the chart to one webhook endpoint.
timeseries?: TimeseriesPoint[] | undefined;
Bucketed delivery metrics.
timestamp?: string | undefined;
Start time for the returned bucket.
total_events?: number | undefined;
Currently always `0` in the returned timeseries payload.
total_deliveries?: number | undefined;
Total deliveries in the bucket.
successful_deliveries?: number | undefined;
Successful deliveries in the bucket.
failed_deliveries?: number | undefined;
Failed deliveries in the bucket.
filtered_deliveries?: number | undefined;
Filtered deliveries in the bucket.
avg_response_time_ms?: number | undefined | undefined;
Average response time in milliseconds for the bucket.
success_rate?: number | undefined;
Success rate for the bucket.
interval?: string | undefined;
Resolved bucket interval returned by the backend.
loading?: boolean | undefined;
Whether the timeseries query is still loading.
error?: unknown | undefined;
SWR error for the timeseries query.
refetch?: () => void | undefined;
Revalidates the timeseries query.

API Identity

useApiAuthAppSession()

useApiAuthAppSession() is the entry hook for the API identity surface. It exchanges an optional ticket, loads the current API auth app session, and returns the app metadata that the vanity API auth provider uses to gate the overview, keys, and access-log pages.

import { useApiAuthAppSession } from '@wacht/nextjs';export default function ApiIdentityShell({  ticket,}: {  ticket?: string | null;}) {  const {    hasSession,    sessionLoading,    apiAuthApp,  } = useApiAuthAppSession(ticket);  if (sessionLoading) {    return <div>Loading API identity...</div>;  }  if (!hasSession) {    return <div>Access required</div>;  }  return (    <div>      <h1>{apiAuthApp?.name}</h1>      <p>{apiAuthApp?.key_prefix}</p>    </div>  );}
ticket?: string | null | undefined | undefined;
Optional session ticket for the API identity surface.
hasSession?: boolean | undefined;
Whether the current user has a valid API identity session.
sessionLoading?: boolean | undefined;
True while the ticket exchange or the session fetch is still running.
sessionError?: Error | null | undefined;
Transport or exchange failure. A missing session is not surfaced as an error here.
sessionId?: string | null | undefined;
Current API identity session identifier.
apiAuthApp?: ApiAuthAppInfo | null | undefined;
Current API identity app metadata.
id?: string | undefined;
App identifier.
app_slug?: string | undefined;
App slug.
name?: string | undefined;
App name.
key_prefix?: string | undefined;
Prefix used when rendering API keys for this app.
description?: string | undefined | undefined;
Optional app description.
is_active?: boolean | undefined;
Whether the app is active.
rate_limits?: RateLimit[] | undefined;
Configured app-level rate limits.
unit?: 'millisecond' | 'second' | 'minute' | 'hour' | 'day' | 'calendar_day' | 'month' | 'calendar_month' | undefined;
Rate-limit time unit.
duration?: number | undefined;
Duration value for the limit window.
max_requests?: number | undefined;
Maximum requests allowed in that window.
mode?: 'per_app' | 'per_key' | 'per_key_and_ip' | 'per_app_and_ip' | undefined | undefined;
Scope of the rate limit.
ticketExchanged?: boolean | undefined;
Whether the supplied ticket has already been exchanged successfully.
ticketLoading?: boolean | undefined;
Whether the ticket exchange is still in progress.
refetch?: () => Promise<void> | undefined;
Revalidates the current API identity session.

useApiAuthKeys()

useApiAuthKeys() is the main key-management hook for the API identity surface. It lists keys for the current app, lets you filter by status, and exposes the three lifecycle mutations that the vanity keys page uses directly: create, rotate, and revoke.

import { useState } from 'react';import { useApiAuthKeys } from '@wacht/nextjs';export default function KeysPage() {  const [status, setStatus] = useState<'active' | 'revoked' | 'all'>('active');  const { keys, loading, createKey, rotateKey, revokeKey } = useApiAuthKeys({    status,  });  if (loading) {    return <div>Loading keys...</div>;  }  return (    <div>      <button        onClick={async () => {          const result = await createKey({ name: 'Production Backend' });          console.log(result.data.secret);        }}      >        Create key      </button>      <ul>        {keys.map((key) => (          <li key={key.id}>            {key.name}            <button onClick={async () => {              const result = await rotateKey({ key_id: key.id });              console.log(result.data.secret);            }}>Rotate</button>            <button onClick={async () => {              await revokeKey({ key_id: key.id });            }}>Revoke</button>          </li>        ))}      </ul>    </div>  );}
filters?: UseApiAuthKeysFilters | undefined | undefined;
Optional key-list filters.
status?: 'active' | 'revoked' | 'all' | undefined | undefined;
Status filter for the key list.
keys?: ApiKey[] | undefined;
API keys for the current app under the current filter.
id?: string | undefined;
Key identifier.
name?: string | undefined;
Human-readable key name.
key_prefix?: string | undefined;
Public key prefix.
key_suffix?: string | undefined;
Public key suffix used when displaying a partially masked key.
permissions?: string[] | undefined;
Explicit permissions attached to the key.
org_role_permissions?: string[] | undefined;
Organization-role-derived permissions attached to the key.
workspace_role_permissions?: string[] | undefined;
Workspace-role-derived permissions attached to the key.
organization_id?: string | undefined | undefined;
Bound organization scope when the key is organization-scoped.
workspace_id?: string | undefined | undefined;
Bound workspace scope when the key is workspace-scoped.
organization_membership_id?: string | undefined | undefined;
Bound organization membership when the key is tied to a specific membership.
workspace_membership_id?: string | undefined | undefined;
Bound workspace membership when the key is tied to a specific membership.
expires_at?: string | undefined | undefined;
Expiry timestamp when the key is time-limited.
last_used_at?: string | undefined | undefined;
Last usage timestamp when available.
is_active?: boolean | undefined;
Whether the key is still active.
created_at?: string | undefined;
Creation timestamp.
revoked_at?: string | undefined | undefined;
Revocation timestamp when the key has been revoked.
revoked_reason?: string | undefined | undefined;
Revocation reason when one was recorded.
createKey?: (input: CreateApiAuthKeyInput) => Promise<ApiResult<ApiKeyWithSecret>> | undefined;
Creates a new API key and returns the envelope. The one-time secret payload is available on `result.data`.
input.name?: string | undefined;
Name for the new key.
input.expires_at?: string | undefined | undefined;
Optional expiry timestamp in ISO format.
result.data.id?: string | undefined;
New key identifier.
result.data.name?: string | undefined;
New key name.
result.data.key_prefix?: string | undefined;
New key prefix.
result.data.key_suffix?: string | undefined;
New key suffix.
result.data.permissions?: string[] | undefined;
Permissions attached to the new key.
result.data.expires_at?: string | undefined | undefined;
Expiry timestamp when present.
result.data.last_used_at?: string | undefined | undefined;
Last-used timestamp when present.
result.data.is_active?: boolean | undefined;
Whether the newly created key is active.
result.data.created_at?: string | undefined;
Creation timestamp.
result.data.revoked_at?: string | undefined | undefined;
Revocation timestamp when present.
result.data.revoked_reason?: string | undefined | undefined;
Revocation reason when present.
result.data.secret?: string | undefined;
One-time secret value. This is the sensitive value the UI should reveal once and then discard.
rotateKey?: (input: RotateApiAuthKeyInput) => Promise<ApiResult<ApiKeyWithSecret>> | undefined;
Rotates an existing API key and returns the envelope. The replacement secret is available on `result.data`.
input.key_id?: string | undefined;
Identifier of the key to rotate.
result.data.secret?: string | undefined;
One-time replacement secret returned by the rotation flow.
revokeKey?: (input: RevokeApiAuthKeyInput) => Promise<ApiResult<void>> | undefined;
Revokes an API key and refreshes the list.
input.key_id?: string | undefined;
Identifier of the key to revoke.
input.reason?: string | undefined | undefined;
Optional revocation reason.
loading?: boolean | undefined;
Whether the list query is still loading.
error?: unknown | undefined;
SWR error for the key list query.
refetch?: () => void | undefined;
Revalidates the key list.

useApiAuthAuditLogs()

useApiAuthAuditLogs() is the paginated log hook behind the API identity access-logs page. It returns one page of audit records at a time, plus the paging metadata that the vanity logs view uses to move forward with a cursor and rebuild the query when filters change.

import { useMemo, useState } from 'react';import { addDays } from 'date-fns';import { useApiAuthAuditLogs } from '@wacht/nextjs';export default function AccessLogsPage() {  const [page, setPage] = useState(1);  const [cursors, setCursors] = useState<string[]>([]);  const [outcome, setOutcome] = useState<'all' | 'allowed' | 'blocked'>('all');  const startDate = useMemo(() => {    const d = addDays(new Date(), -7);    d.setHours(0, 0, 0, 0);    return d.toISOString();  }, []);  const endDate = useMemo(() => {    const d = new Date();    d.setHours(23, 59, 59, 999);    return d.toISOString();  }, []);  const cursor = page > 1 ? cursors[page - 2] : undefined;  const { logs, has_more, next_cursor, loading } = useApiAuthAuditLogs({    limit: 25,    cursor,    outcome: outcome === 'all' ? undefined : outcome,    start_date: startDate,    end_date: endDate,  });  if (!loading && next_cursor && page === cursors.length + 1) {    setCursors((prev) => [...prev, next_cursor]);  }  return (    <div>      <button onClick={() => setOutcome('blocked')}>Blocked only</button>      <ul>        {logs.map((log) => (          <li key={log.request_id}>{log.path}</li>        ))}      </ul>      <button disabled={!has_more} onClick={() => setPage((current) => current + 1)}>        Next      </button>    </div>  );}
options?: UseApiAuthAuditLogsOptions | undefined | undefined;
Optional log-query filters.
limit?: number | undefined | undefined;
Maximum number of records to request.
cursor?: string | undefined | undefined;
Cursor for the current page.
outcome?: 'allowed' | 'blocked' | undefined | undefined;
Filters the audit logs by request outcome.
key_id?: string | undefined | undefined;
Filters the logs to a single API key.
start_date?: string | undefined | undefined;
Lower timestamp bound in ISO format.
end_date?: string | undefined | undefined;
Upper timestamp bound in ISO format.
logs?: ApiAuditLog[] | undefined;
Current page of access-log records.
request_id?: string | undefined;
Request identifier.
deployment_id?: number | undefined;
Numeric deployment identifier.
app_slug?: string | undefined;
API auth app slug.
key_id?: number | undefined;
Numeric key identifier.
key_name?: string | undefined;
Key name at the time of the request.
outcome?: string | undefined;
Request outcome, such as allowed or blocked.
blocked_by_rule?: string | undefined | undefined;
Blocking rule when the request was rejected.
client_ip?: string | undefined;
Client IP address.
path?: string | undefined;
Requested path.
user_agent?: string | undefined;
User agent string.
rate_limits?: string | undefined | undefined;
Rate-limit summary when the request touched rate-limit logic.
timestamp?: string | undefined;
Request timestamp.
limit?: number | undefined;
Effective page size returned by the hook.
has_more?: boolean | undefined;
Whether another page is available after the current one.
next_cursor?: string | undefined | undefined;
Cursor for the next page when one exists.
loading?: boolean | undefined;
Whether the current log query is still loading.
error?: unknown | undefined;
SWR error for the current log query.
refetch?: () => void | undefined;
Revalidates the current log page.

useApiAuthAuditAnalytics()

useApiAuthAuditAnalytics() is the overview analytics hook for API identity. It returns aggregate request counts and optional breakdown sections for keys, paths, blocked reasons, and rate-limit rules. In vanity-pages, the API identity overview uses it alongside useApiAuthAuditTimeseries() to power the top metrics and breakdown cards.

import { addDays } from 'date-fns';import { useApiAuthAuditAnalytics } from '@wacht/nextjs';export default function ApiIdentityOverview() {  const start = addDays(new Date(), -7).toISOString();  const end = new Date().toISOString();  const { analytics, loading } = useApiAuthAuditAnalytics({    start_date: start,    end_date: end,    include_top_keys: true,    include_top_paths: true,    include_blocked_reasons: true,    include_rate_limits: true,  });  if (loading) {    return <div>Loading analytics...</div>;  }  return (    <div>      <p>Total requests: {analytics?.total_requests}</p>      <p>Success rate: {analytics?.success_rate}</p>    </div>  );}
options?: UseApiAuthAuditAnalyticsOptions | undefined | undefined;
Optional analytics filters and include flags.
start_date?: string | undefined | undefined;
Lower timestamp bound in ISO format.
end_date?: string | undefined | undefined;
Upper timestamp bound in ISO format.
key_id?: string | undefined | undefined;
Restricts the analytics to one key.
include_top_keys?: boolean | undefined | undefined;
Requests the `top_keys` section.
include_top_paths?: boolean | undefined | undefined;
Requests the `top_paths` section.
include_blocked_reasons?: boolean | undefined | undefined;
Requests the `blocked_reasons` section.
include_rate_limits?: boolean | undefined | undefined;
Requests the `rate_limit_stats` section.
top_limit?: number | undefined | undefined;
Limits the size of the optional top lists.
analytics?: ApiAuditAnalyticsResponse | null | undefined;
Aggregate analytics payload for the current query window.
total_requests?: number | undefined;
Total requests in the selected window.
allowed_requests?: number | undefined;
Allowed requests in the selected window.
blocked_requests?: number | undefined;
Blocked requests in the selected window.
success_rate?: number | undefined;
Allowed-request rate as a percentage-like number from the backend analytics response.
keys_used_24h?: number | undefined;
Distinct keys used in the last 24 hours.
top_keys?: KeyStatsItem[] | undefined | undefined;
Top keys section when `include_top_keys` is requested.
key_id?: number | undefined;
Numeric key identifier.
key_name?: string | undefined;
Key name.
total_requests?: number | undefined;
Total requests attributed to that key.
top_paths?: PathStatsItem[] | undefined | undefined;
Top paths section when `include_top_paths` is requested.
path?: string | undefined;
Observed request path.
total_requests?: number | undefined;
Total requests for that path.
blocked_reasons?: BlockedReasonItem[] | undefined | undefined;
Blocked reason breakdown when `include_blocked_reasons` is requested.
blocked_by_rule?: string | undefined;
Blocking rule identifier.
count?: number | undefined;
Blocked request count for that rule.
percentage?: number | undefined;
Percentage share for that rule.
rate_limit_stats?: RateLimitBreakdown | undefined | undefined;
Rate-limit breakdown when `include_rate_limits` is requested.
total_hits?: number | undefined;
Total rate-limit hits.
percentage_of_blocked?: number | undefined;
Share of blocked requests caused by rate limits.
top_rules?: RateLimitStatsItem[] | undefined | undefined;
Top triggered rate-limit rules.
rule?: string | undefined;
Rule identifier.
hit_count?: number | undefined;
Number of hits for that rule.
percentage?: number | undefined;
Percentage share for that rule.
loading?: boolean | undefined;
Whether the analytics query is still loading.
error?: unknown | undefined;
SWR error for the analytics query.
refetch?: () => void | undefined;
Revalidates the analytics query.

useApiAuthAuditTimeseries()

useApiAuthAuditTimeseries() returns the time-bucketed request series for the API identity overview charts. It is the hook that vanity-pages uses to build the request activity graph, and it pairs naturally with useApiAuthAuditAnalytics() when you need both the aggregate metrics and the per-interval chart data for the same date range.

import { addDays } from 'date-fns';import { useApiAuthAuditTimeseries } from '@wacht/nextjs';export default function ApiIdentityChart() {  const start = addDays(new Date(), -7).toISOString();  const end = new Date().toISOString();  const { timeseries, interval, loading } = useApiAuthAuditTimeseries({    start_date: start,    end_date: end,    interval: 'day',  });  if (loading) {    return <div>Loading chart…</div>;  }  return (    <div>      <p>Interval: {interval}</p>      <p>Points: {timeseries.length}</p>    </div>  );}
options?: UseApiAuthAuditTimeseriesOptions | undefined | undefined;
Optional timeseries filters.
start_date?: string | undefined | undefined;
Lower timestamp bound in ISO format.
end_date?: string | undefined | undefined;
Upper timestamp bound in ISO format.
interval?: string | undefined | undefined;
Requested time bucket size.
key_id?: string | undefined | undefined;
Restricts the series to one API key.
timeseries?: ApiAuditTimeseriesPoint[] | undefined;
Time-bucketed request points for the current query.
timestamp?: string | undefined;
Bucket timestamp.
total_requests?: number | undefined;
Total requests in the bucket.
allowed_requests?: number | undefined;
Allowed requests in the bucket.
blocked_requests?: number | undefined;
Blocked requests in the bucket.
success_rate?: number | undefined;
Success rate for the bucket.
interval?: string | undefined;
Effective interval returned by the hook.
loading?: boolean | undefined;
Whether the current timeseries query is still loading.
error?: unknown | undefined;
SWR error for the timeseries query.
refetch?: () => void | undefined;
Revalidates the current timeseries query.