Skip to main content

Custom API Services

The Kapa SDK uses an API service to handle communication with the Kapa backend. The SDK includes a default implementation, but you can provide your own implementation for testing or custom networking needs.

Default API serviceโ€‹

By default, the SDK uses the DefaultKapaApiService to communicate with Kapa's backend. This service handles:

  • Submitting user queries and streaming back responses
  • Sending feedback for question-answer pairs
  • Managing request cancellation

Most applications can use the default service without modification.

Custom API service implementationโ€‹

For testing, special networking requirements, or integration with your own middleware, you can create a custom API service by implementing the KapaApiService interface.

API service interfaceโ€‹

interface KapaApiService {
/**
* Post a question to the backend and stream back the answer
*/
submitQuery(args: SubmitQueryArgs, callbacks: ChatStreamCallbacks): Promise<void>;

/**
* Send feedback (๐Ÿ‘ / ๐Ÿ‘Ž) for a specific QA pair
*/
addFeedback(args: SubmitFeedbackArgs): Promise<void>;

/**
* Abort the current network request, if any
*/
abortCurrent(): void;
}

Parameter typesโ€‹

The interface uses the following parameter types:

interface SubmitQueryArgs {
// User's question
query: string;

// Optional thread ID for continuing a conversation
// If null, a new conversation thread will be created
threadId: string | null;

// reCAPTCHA/hCaptcha verification token for bot protection
captcha: CaptchaToken;

// Your Kapa integration ID
integrationId: string;

// User identification data for personalization and tracking
userIdentifiers: UserIdentifiers;

// Additional user metadata for analytics/tracking
userMetadata: UserMetadata;

// The URL where the query was initiated
originUrl: string;
}

interface SubmitFeedbackArgs {
// Unique identifier for the question-answer pair
questionAnswerId: string;

// User's reaction to an answer
reaction: "upvote" | "downvote";

// reCAPTCHA/hCaptcha verification token for bot protection
captcha: CaptchaToken;

// Your Kapa integration ID
integrationId: string;

// Optional user-provided comment/reason
comment?: FeedbackComment;
}

interface ChatStreamCallbacks {
// Called when the first response byte is received
onFirstToken?: () => void;

// Called repeatedly with chunks of the answer
onPartialAnswer?: (partial: string) => void;

// Called with the list of relevant citation sources
onRelevantSources?: (sources: Source[]) => void;

// Called when an error occurs during streaming
onError?: (msg: string) => void;

// Called with thread and QA pair identifiers once they're available
onIdentifiers?: (threadId: string, qaPairId: string) => void;
}

Using a custom API serviceโ€‹

To use a custom API service, pass it to the KapaProvider component:

import { KapaProvider } from '@kapaai/react-sdk';
import { MyCustomApiService } from './my-custom-api-service';

function App() {
// Create an instance of your custom API service
const customApiService = new MyCustomApiService();

return (
<KapaProvider
integrationId="your-integration-id"
callbacks={{...}}
apiService={customApiService}
>
<YourApplication />
</KapaProvider>
);
}

Example: Creating a test mock serviceโ€‹

Here's an example of creating a mock API service for testing:

import { 
KapaApiService,
SubmitQueryArgs,
SubmitFeedbackArgs,
ChatStreamCallbacks
} from '@kapaai/react-sdk';

export class MockKapaApiService implements KapaApiService {
async submitQuery(
args: SubmitQueryArgs,
callbacks: ChatStreamCallbacks
): Promise<void> {
// Simulate connection setup
await new Promise(resolve => setTimeout(resolve, 500));

// Simulate first token received
callbacks.onFirstToken?.();

// Simulate a thread ID
const threadId = 'mock-thread-123';
const qaPairId = 'mock-qa-456';
callbacks.onIdentifiers?.(threadId, qaPairId);

// Simulate streaming answer chunks
const answerChunks = [
"Hello! I'm ",
"a mock ",
"AI assistant. ",
"How can I help you today?"
];

for (const chunk of answerChunks) {
await new Promise(resolve => setTimeout(resolve, 300));
callbacks.onPartialAnswer?.(chunk);
}

// Simulate sources
callbacks.onRelevantSources?.([
{
title: "Mock Documentation",
subtitle: "Getting Started Guide",
source_url: "https://example.com/docs",
source_type: "webpage"
}
]);
}

async addFeedback(args: SubmitFeedbackArgs): Promise<void> {
console.log('Mock feedback submitted:', args);
// Simulate network delay
await new Promise(resolve => setTimeout(resolve, 300));
// Return success (no throw = success)
}

abortCurrent(): void {
console.log('Mock abort called');
// Implementation would cancel any ongoing simulations
}
}