Hooks

All hooks must be used inside a <HookbasePortal> provider. They provide data fetching, caching (via React Query), and mutation methods for building custom portal UIs.

useEndpoints

Fetches all endpoints and provides CRUD + secret rotation methods.

const {
  // Query
  endpoints,        // Endpoint[]
  isLoading,        // boolean
  isError,          // boolean
  error,            // Error | null
  refetch,          // () => Promise<...>
 
  // Mutations
  createEndpoint,   // (data: CreateEndpointInput) => Promise<ApiResponse<EndpointWithSecret>>
  isCreating,       // boolean
  createError,      // Error | null
 
  updateEndpoint,   // (id: string, data: UpdateEndpointInput) => Promise<ApiResponse<Endpoint>>
  isUpdating,       // boolean
  updateError,      // Error | null
 
  deleteEndpoint,   // (id: string) => Promise<void>
  isDeleting,       // boolean
  deleteError,      // Error | null
 
  rotateSecret,     // (id: string) => Promise<ApiResponse<{ secret: string }>>
  isRotating,       // boolean
} = useEndpoints();

Example — Custom Create Form

function CreateEndpointButton() {
  const { createEndpoint, isCreating } = useEndpoints();
 
  const handleCreate = async () => {
    const result = await createEndpoint({
      url: 'https://example.com/webhooks',
      description: 'Production endpoint',
    });
    // result.data.secret — save this! Only shown once.
    alert(`Secret: ${result.data.secret}`);
  };
 
  return (
    <button onClick={handleCreate} disabled={isCreating}>
      {isCreating ? 'Creating...' : 'Create Endpoint'}
    </button>
  );
}

Input Types

interface CreateEndpointInput {
  url: string;
  description?: string;
}
 
interface UpdateEndpointInput {
  url?: string;
  description?: string;
  isDisabled?: boolean;
}

useEndpoint

Fetches a single endpoint by ID.

const {
  data,       // Endpoint | undefined
  isLoading,  // boolean
  isError,    // boolean
  error,      // Error | null
} = useEndpoint(endpointId);

The query is disabled when endpointId is falsy.


useEventTypes

Fetches available event types with automatic category grouping.

const {
  eventTypes,         // EventType[]
  groupedByCategory,  // Record<string, EventType[]>
  categories,         // string[] (sorted)
  isLoading,          // boolean
  isError,            // boolean
  error,              // Error | null
  refetch,            // () => Promise<...>
} = useEventTypes();

Results are cached for 5 minutes (staleTime: 300000).

Example — Category List

function EventCatalog() {
  const { groupedByCategory, categories, isLoading } = useEventTypes();
 
  if (isLoading) return <p>Loading...</p>;
 
  return (
    <div>
      {categories.map(category => (
        <div key={category}>
          <h3>{category}</h3>
          <ul>
            {groupedByCategory[category].map(et => (
              <li key={et.id}>
                <code>{et.name}</code>{et.description}
              </li>
            ))}
          </ul>
        </div>
      ))}
    </div>
  );
}

useSubscriptions

Manages event type subscriptions for an endpoint.

const {
  // Query
  subscriptions,          // Subscription[]
  subscribedEventTypeIds, // Set<string>
  isLoading,              // boolean
  isError,                // boolean
  error,                  // Error | null
  refetch,                // () => Promise<...>
 
  // Mutations
  createSubscription,     // (data: CreateSubscriptionInput) => Promise<ApiResponse<Subscription>>
  isCreating,             // boolean
  createError,            // Error | null
 
  deleteSubscription,     // (id: string) => Promise<void>
  isDeleting,             // boolean
  deleteError,            // Error | null
 
  // Convenience
  toggleSubscription,     // (eventTypeId: string, endpointId: string) => Promise<void>
} = useSubscriptions(endpointId?);

Example — Toggle Subscriptions

function SubscriptionToggle({ endpointId, eventType }) {
  const { subscribedEventTypeIds, toggleSubscription } = useSubscriptions(endpointId);
  const isSubscribed = subscribedEventTypeIds.has(eventType.id);
 
  return (
    <label>
      <input
        type="checkbox"
        checked={isSubscribed}
        onChange={() => toggleSubscription(eventType.id, endpointId)}
      />
      {eventType.name}
    </label>
  );
}

useMessages

Fetches paginated delivery messages with optional filtering and auto-refresh.

const {
  messages,    // OutboundMessage[]
  total,       // number
  isLoading,   // boolean
  isError,     // boolean
  error,       // Error | null
  refetch,     // () => Promise<...>
  isFetching,  // boolean (true during background refetch)
} = useMessages(options?);

Options — UseMessagesOptions

OptionTypeDefaultDescription
endpointIdstringFilter by endpoint
status'pending' | 'success' | 'failed' | 'exhausted'Filter by status
limitnumberPage size
offsetnumberPagination offset
refreshIntervalnumber0Auto-refresh interval in ms

Example

function FailedMessages({ endpointId }) {
  const { messages, total, isLoading } = useMessages({
    endpointId,
    status: 'failed',
    limit: 10,
    refreshInterval: 15000,
  });
 
  if (isLoading) return <p>Loading...</p>;
 
  return (
    <div>
      <p>{total} failed messages</p>
      {messages.map(msg => (
        <div key={msg.id}>
          <code>{msg.eventType}</code>{msg.attempts} attempts
        </div>
      ))}
    </div>
  );
}

useMessage

Fetches a single message by ID.

const {
  data,       // OutboundMessage | undefined
  isLoading,  // boolean
  isError,    // boolean
  error,      // Error | null
} = useMessage(messageId);

useApplication

Fetches the current application info (name, ID, organization).

const {
  application,  // Application | undefined
  isLoading,    // boolean
  isError,      // boolean
  error,        // Error | null
  refetch,      // () => Promise<...>
} = useApplication();

Application Type

interface Application {
  id: string;
  name: string;
  organizationId: string;
}

useTestEndpoint

Sends a test event to an endpoint and tracks the result.

const {
  testEndpoint,  // (endpointId: string, eventType?: string) => Promise<TestDeliveryResult>
  isTesting,     // boolean
  testResult,    // TestDeliveryResult | null
  testError,     // Error | null
  clearResult,   // () => void
} = useTestEndpoint();

TestDeliveryResult

interface TestDeliveryResult {
  success: boolean;
  testEvent: {
    id: string;
    type: string;
    timestamp: string;
  };
  delivery: {
    status: 'success' | 'failed';
    responseStatus: number;
    responseTimeMs: number;
    responseBody: string;
    errorMessage: string | null;
  };
  signature: {
    header: string;
    value: string;
    timestamp: number;
  };
}

Example

function TestButton({ endpointId }) {
  const { testEndpoint, isTesting, testResult } = useTestEndpoint();
 
  return (
    <div>
      <button
        onClick={() => testEndpoint(endpointId)}
        disabled={isTesting}
      >
        {isTesting ? 'Sending...' : 'Send Test Event'}
      </button>
 
      {testResult && (
        <p>
          {testResult.success ? 'Success' : 'Failed'}
          {testResult.delivery.responseStatus} in {testResult.delivery.responseTimeMs}ms
        </p>
      )}
    </div>
  );
}

useReplay

Replays failed messages — single message or bulk for an endpoint.

const {
  replayMessage,            // (messageId: string) => Promise<ReplayResult>
  replayFailedForEndpoint,  // (endpointId: string) => Promise<BulkReplayResult>
  isReplaying,              // boolean
  replayError,              // Error | null
} = useReplay();

Return Types

interface ReplayResult {
  originalMessageId: string;
  newMessageId: string;
  status: string;
}
 
interface BulkReplayResult {
  replayed: number;
  newMessageIds: string[];
}

Example

function RetryButton({ message }) {
  const { replayMessage, isReplaying } = useReplay();
 
  return (
    <button
      onClick={() => replayMessage(message.id)}
      disabled={isReplaying || message.status === 'success'}
    >
      {isReplaying ? 'Retrying...' : 'Retry'}
    </button>
  );
}

useHookbase

Access the low-level portal context (API client, token, base URL).

const {
  api,     // PortalApiClient
  token,   // string
  apiUrl,  // string
} = useHookbase();

Use this when you need to call the API client directly, for example to verify an endpoint:

const { api } = useHookbase();
const result = await api.verifyEndpoint(endpointId);

See the Portal API Reference for all available client methods.


useTheme

Access the current theme and dark mode state.

const {
  theme,   // HookbaseTheme
  isDark,  // boolean
} = useTheme();