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",
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
}
}