-
Notifications
You must be signed in to change notification settings - Fork 437
feat: setup Convolo AI plugin #1018
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,61 @@ | ||||||||||||||||||||||||||||||||||||||||
| import type { ApiRequestOptions } from 'corsair/http'; | ||||||||||||||||||||||||||||||||||||||||
| import type { OpenAPIConfig } from 'corsair/http'; | ||||||||||||||||||||||||||||||||||||||||
| import { request } from 'corsair/http'; | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| export class ConvoloAiAPIError extends Error { | ||||||||||||||||||||||||||||||||||||||||
| constructor( | ||||||||||||||||||||||||||||||||||||||||
| message: string, | ||||||||||||||||||||||||||||||||||||||||
| public readonly code?: string, | ||||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||||
| super(message); | ||||||||||||||||||||||||||||||||||||||||
| this.name = 'ConvoloAiAPIError'; | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| // TODO: Update with your API base URL | ||||||||||||||||||||||||||||||||||||||||
| const CONVOLOAI_API_BASE = 'https://api.example.com'; | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| export async function makeConvoloAiRequest<T>( | ||||||||||||||||||||||||||||||||||||||||
| endpoint: string, | ||||||||||||||||||||||||||||||||||||||||
| apiKey: string, | ||||||||||||||||||||||||||||||||||||||||
| options: { | ||||||||||||||||||||||||||||||||||||||||
| method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'; | ||||||||||||||||||||||||||||||||||||||||
| body?: Record<string, unknown>; | ||||||||||||||||||||||||||||||||||||||||
| query?: Record<string, string | number | boolean | undefined>; | ||||||||||||||||||||||||||||||||||||||||
| } = {}, | ||||||||||||||||||||||||||||||||||||||||
| ): Promise<T> { | ||||||||||||||||||||||||||||||||||||||||
| const { method = 'GET', body, query } = options; | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| const config: OpenAPIConfig = { | ||||||||||||||||||||||||||||||||||||||||
| BASE: CONVOLOAI_API_BASE, | ||||||||||||||||||||||||||||||||||||||||
| VERSION: '1.0.0', | ||||||||||||||||||||||||||||||||||||||||
| WITH_CREDENTIALS: false, | ||||||||||||||||||||||||||||||||||||||||
| CREDENTIALS: 'omit', | ||||||||||||||||||||||||||||||||||||||||
| TOKEN: apiKey, | ||||||||||||||||||||||||||||||||||||||||
| HEADERS: { | ||||||||||||||||||||||||||||||||||||||||
| 'Content-Type': 'application/json', | ||||||||||||||||||||||||||||||||||||||||
| // TODO: Add authentication headers | ||||||||||||||||||||||||||||||||||||||||
| // 'Authorization': \`Bearer \${apiKey}\` | ||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| const requestOptions: ApiRequestOptions = { | ||||||||||||||||||||||||||||||||||||||||
| method, | ||||||||||||||||||||||||||||||||||||||||
| url: endpoint, | ||||||||||||||||||||||||||||||||||||||||
| body: | ||||||||||||||||||||||||||||||||||||||||
| method === 'POST' || method === 'PUT' || method === 'PATCH' | ||||||||||||||||||||||||||||||||||||||||
| ? body | ||||||||||||||||||||||||||||||||||||||||
| : undefined, | ||||||||||||||||||||||||||||||||||||||||
| mediaType: 'application/json; charset=utf-8', | ||||||||||||||||||||||||||||||||||||||||
| query: method === 'GET' ? query : undefined, | ||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||
| return await request<T>(config, requestOptions); | ||||||||||||||||||||||||||||||||||||||||
| } catch (error) { | ||||||||||||||||||||||||||||||||||||||||
| if (error instanceof Error) { | ||||||||||||||||||||||||||||||||||||||||
| throw new ConvoloAiAPIError(error.message); | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
| throw new ConvoloAiAPIError('Unknown error'); | ||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+55
to
+59
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When the provider returns HTTP 429 after transport retries, replacing Rule Used: Every endpoint must validate inputs and outputs wi... (source) Knowledge Base Used:
Comment on lines
+53
to
+59
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- packages/convoloai/client.ts ---'
cat -n packages/convoloai/client.ts
printf '%s\n' '--- packages/convoloai/error-handlers.ts ---'
cat -n packages/convoloai/error-handlers.ts
printf '%s\n' '--- request implementation ---'
sed -n '300,460p' packages/corsair/async-core/request.ts
printf '%s\n' '--- ApiError definitions and usages ---'
rg -n -C 4 'class ApiError|interface ApiError|type ApiError|retryAfter|instanceof ApiError|ConvoloAiAPIError' packagesRepository: corsairdev/corsair Length of output: 50375 🏁 Script executed: #!/bin/bash
set -eu
log=/tmp/coderabbit-shell-logs/shell-output-qQJQSy
printf '%s\n' '--- client and handler sections ---'
rg -n '^--- packages/(convoloai/(client|error-handlers)\.ts|corsair/async-core/request\.ts) ---|^--- request implementation ---|^packages/convoloai/client\.ts|^packages/convoloai/error-handlers\.ts' "$log" | head -30
printf '%s\n' '--- ApiError declaration ---'
rg -n -C 8 'class ApiError' packages/corsair packages/convoloai
printf '%s\n' '--- exact ConvoloAI references ---'
rg -n -C 8 'ConvoloAiAPIError|ApiError|retryAfter|status' packages/convoloaiRepository: corsairdev/corsair Length of output: 8837 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- packages/convoloai/client.ts ---'
cat -n packages/convoloai/client.ts
printf '%s\n' '--- packages/convoloai/error-handlers.ts ---'
cat -n packages/convoloai/error-handlers.ts
printf '%s\n' '--- packages/corsair/async-core/request.ts ---'
cat -n packages/corsair/async-core/request.ts | sed -n '333,439p'
printf '%s\n' '--- packages/corsair/async-core/ApiError.ts ---'
cat -n packages/corsair/async-core/ApiError.ts | sed -n '100,155p'Repository: corsairdev/corsair Length of output: 8027 Preserve When Proposed fix-import type { ApiRequestOptions } from 'corsair/http';
+import { ApiError, type ApiRequestOptions } from 'corsair/http';
@@
} catch (error) {
+ if (error instanceof ApiError) {
+ throw error;
+ }
if (error instanceof Error) {
throw new ConvoloAiAPIError(error.message);
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| import { logEventFromContext } from 'corsair/core'; | ||
| import type { ConvoloAiEndpoints } from '..'; | ||
| import type { ConvoloAiEndpointOutputs } from './types'; | ||
| import { makeConvoloAiRequest } from '../client'; | ||
|
|
||
| export const get: ConvoloAiEndpoints['exampleGet'] = async (ctx, input) => { | ||
| const response = await makeConvoloAiRequest<ConvoloAiEndpointOutputs['exampleGet']>( | ||
| `example/${input.id}`, | ||
| ctx.key, | ||
| { method: 'GET' }, | ||
| ); | ||
|
|
||
| await logEventFromContext(ctx, 'convoloai.example.get', { ...input }, 'completed'); | ||
| return response; | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| import { get as exampleGet } from './example'; | ||
|
|
||
| export const Example = { | ||
| get: exampleGet, | ||
| }; | ||
|
|
||
| export * from './types'; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| import { z } from 'zod'; | ||
|
|
||
| const ExampleGetInputSchema = z.object({ | ||
| id: z.string(), | ||
| }); | ||
|
|
||
| export type ExampleGetInput = z.infer<typeof ExampleGetInputSchema>; | ||
|
|
||
| const ExampleGetResponseSchema = z.object({ | ||
| id: z.string(), | ||
| }); | ||
|
|
||
| export type ExampleGetResponse = z.infer<typeof ExampleGetResponseSchema>; | ||
|
|
||
| export type ConvoloAiEndpointInputs = { | ||
| exampleGet: ExampleGetInput; | ||
| }; | ||
|
|
||
| export type ConvoloAiEndpointOutputs = { | ||
| exampleGet: ExampleGetResponse; | ||
| }; | ||
|
|
||
| export const ConvoloAiEndpointInputSchemas = { | ||
| exampleGet: ExampleGetInputSchema, | ||
| } as const; | ||
|
|
||
| export const ConvoloAiEndpointOutputSchemas = { | ||
| exampleGet: ExampleGetResponseSchema, | ||
| } as const; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| import { ApiError } from 'corsair/http'; | ||
| import type { CorsairErrorHandler } from 'corsair/core'; | ||
|
|
||
| export const errorHandlers = { | ||
| RATE_LIMIT_ERROR: { | ||
| match: (error: Error) => { | ||
| if (error instanceof ApiError && error.status === 429) return true; | ||
| const msg = error.message.toLowerCase(); | ||
| return msg.includes('rate_limited') || msg.includes('429'); | ||
| }, | ||
| handler: async (error: Error) => { | ||
| let retryAfterMs: number | undefined; | ||
| if (error instanceof ApiError && error.retryAfter !== undefined) { | ||
| retryAfterMs = error.retryAfter; | ||
| } | ||
| return { maxRetries: 5, headersRetryAfterMs: retryAfterMs }; | ||
| }, | ||
| }, | ||
| AUTH_ERROR: { | ||
| match: (error: Error) => { | ||
| if (error instanceof ApiError && error.status === 401) return true; | ||
| const msg = error.message.toLowerCase(); | ||
| return msg.includes('unauthorized') || msg.includes('invalid_auth'); | ||
| }, | ||
| handler: async () => ({ maxRetries: 0 }), | ||
| }, | ||
| DEFAULT: { | ||
| match: () => true, | ||
| handler: async () => ({ maxRetries: 0 }), | ||
| }, | ||
| } satisfies CorsairErrorHandler; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,202 @@ | ||
| import type { | ||
| BindEndpoints, | ||
| BindWebhooks, | ||
| CorsairEndpoint, | ||
| CorsairErrorHandler, | ||
| CorsairPlugin, | ||
| CorsairPluginContext, | ||
| CorsairWebhook, | ||
| KeyBuilderContext, | ||
| PickAuth, | ||
| PluginAuthConfig, | ||
| PluginPermissionsConfig, | ||
| RequiredPluginEndpointMeta, | ||
| RequiredPluginEndpointSchemas, | ||
| RequiredPluginWebhookSchemas, | ||
| } from 'corsair/core'; | ||
| import type { AuthTypes } from 'corsair/core'; | ||
| import type { ConvoloAiEndpointInputs, ConvoloAiEndpointOutputs } from './endpoints/types'; | ||
| import { ConvoloAiEndpointInputSchemas, ConvoloAiEndpointOutputSchemas } from './endpoints/types'; | ||
| import type { | ||
| ConvoloAiWebhookOutputs, | ||
| ExampleEvent, | ||
| } from './webhooks/types'; | ||
| import { ExampleEventSchema } from './webhooks/types'; | ||
| import { Example } from './endpoints'; | ||
| import { ConvoloAiSchema } from './schema'; | ||
| import { ExampleWebhooks } from './webhooks'; | ||
| import { errorHandlers } from './error-handlers'; | ||
| import { matchConvoloAiTenantWebhook } from './webhooks/tenant-matcher'; | ||
| import { resolveConvoloAiOAuthWebhookTenantLink } from './webhooks/oauth-tenant-link'; | ||
|
|
||
| export type ConvoloAiPluginOptions = { | ||
| authType?: PickAuth<'api_key' | 'oauth_2'>; | ||
| key?: string; | ||
| webhookSecret?: string; | ||
| hooks?: InternalConvoloAiPlugin['hooks']; | ||
| webhookHooks?: InternalConvoloAiPlugin['webhookHooks']; | ||
| errorHandlers?: CorsairErrorHandler; | ||
| permissions?: PluginPermissionsConfig<typeof convoloAiEndpointsNested>; | ||
| }; | ||
|
|
||
| export type ConvoloAiContext = CorsairPluginContext< | ||
| typeof ConvoloAiSchema, | ||
| ConvoloAiPluginOptions | ||
| >; | ||
|
|
||
| export type ConvoloAiKeyBuilderContext = KeyBuilderContext<ConvoloAiPluginOptions>; | ||
|
|
||
| export type ConvoloAiBoundEndpoints = BindEndpoints<typeof convoloAiEndpointsNested>; | ||
|
|
||
| type ConvoloAiEndpoint< | ||
| K extends keyof ConvoloAiEndpointOutputs, | ||
| > = CorsairEndpoint< | ||
| ConvoloAiContext, | ||
| ConvoloAiEndpointInputs[K], | ||
| ConvoloAiEndpointOutputs[K] | ||
| >; | ||
|
|
||
| export type ConvoloAiEndpoints = { | ||
| exampleGet: ConvoloAiEndpoint<'exampleGet'>; | ||
| }; | ||
|
|
||
| type ConvoloAiWebhook< | ||
| K extends keyof ConvoloAiWebhookOutputs, | ||
| TEvent, | ||
| > = CorsairWebhook<ConvoloAiContext, TEvent, ConvoloAiWebhookOutputs[K]>; | ||
|
|
||
| export type ConvoloAiWebhooks = { | ||
| example: ConvoloAiWebhook<'example', ExampleEvent>; | ||
| }; | ||
|
|
||
| export type ConvoloAiBoundWebhooks = BindWebhooks<ConvoloAiWebhooks>; | ||
|
|
||
| const convoloAiEndpointsNested = { | ||
| example: { | ||
| get: Example.get, | ||
| }, | ||
| } as const; | ||
|
|
||
| const convoloAiWebhooksNested = { | ||
| example: { | ||
| example: ExampleWebhooks.example, | ||
| }, | ||
| } as const; | ||
|
|
||
| export const convoloAiEndpointSchemas = { | ||
| 'example.get': { | ||
| input: ConvoloAiEndpointInputSchemas.exampleGet, | ||
| output: ConvoloAiEndpointOutputSchemas.exampleGet, | ||
| }, | ||
| } as const satisfies RequiredPluginEndpointSchemas<typeof convoloAiEndpointsNested>; | ||
|
|
||
| const convoloAiWebhookSchemas = { | ||
| 'example.example': { | ||
| description: 'An example webhook event', | ||
| payload: ExampleEventSchema, | ||
| response: ExampleEventSchema, | ||
| }, | ||
| } as const satisfies RequiredPluginWebhookSchemas<typeof convoloAiWebhooksNested>; | ||
|
|
||
| const defaultAuthType: AuthTypes = 'api_key' as const; | ||
|
|
||
| const convoloAiEndpointMeta = { | ||
| 'example.get': { | ||
| riskLevel: 'read', | ||
| description: 'Get an example resource by ID', | ||
| }, | ||
| } as const satisfies RequiredPluginEndpointMeta<typeof convoloAiEndpointsNested>; | ||
|
|
||
| export const convoloAiAuthConfig = { | ||
| api_key: { | ||
| account: ['tenant_external_id'] as const, | ||
| }, | ||
| oauth_2: { | ||
| account: ['tenant_external_id'] as const, | ||
| }, | ||
| } as const satisfies PluginAuthConfig; | ||
|
|
||
| export type BaseConvoloAiPlugin<T extends ConvoloAiPluginOptions> = CorsairPlugin< | ||
| 'convoloai', | ||
| typeof ConvoloAiSchema, | ||
| typeof convoloAiEndpointsNested, | ||
| typeof convoloAiWebhooksNested, | ||
| T, | ||
| typeof defaultAuthType | ||
| >; | ||
|
|
||
| export type InternalConvoloAiPlugin = BaseConvoloAiPlugin<ConvoloAiPluginOptions>; | ||
|
|
||
| export type ExternalConvoloAiPlugin<T extends ConvoloAiPluginOptions> = | ||
| BaseConvoloAiPlugin<T>; | ||
|
|
||
| export function convoloai<const T extends ConvoloAiPluginOptions>( | ||
| incomingOptions: ConvoloAiPluginOptions & T = {} as ConvoloAiPluginOptions & T, | ||
| ): ExternalConvoloAiPlugin<T> { | ||
| const options = { | ||
| ...incomingOptions, | ||
| authType: incomingOptions.authType ?? defaultAuthType, | ||
| }; | ||
| return { | ||
| id: 'convoloai', | ||
| authConfig: convoloAiAuthConfig, | ||
| schema: ConvoloAiSchema, | ||
| options: options, | ||
| hooks: options.hooks, | ||
| webhookHooks: options.webhookHooks, | ||
| endpoints: convoloAiEndpointsNested, | ||
| webhooks: convoloAiWebhooksNested, | ||
| endpointMeta: convoloAiEndpointMeta, | ||
| endpointSchemas: convoloAiEndpointSchemas, | ||
| webhookSchemas: convoloAiWebhookSchemas, | ||
| pluginWebhookMatcher: (request) => { | ||
| const headers = request.headers; | ||
| // TODO: Update to match your webhook signature headers | ||
| return 'x-convoloai-signature' in headers; | ||
| }, | ||
| pluginTenantWebhookMatcher: matchConvoloAiTenantWebhook, | ||
| oauthWebhookTenantLinkResolver: resolveConvoloAiOAuthWebhookTenantLink, | ||
| errorHandlers: { | ||
| ...errorHandlers, | ||
| ...options.errorHandlers, | ||
| }, | ||
| keyBuilder: async (ctx: ConvoloAiKeyBuilderContext, source) => { | ||
| if (source === 'webhook' && options.webhookSecret) { | ||
| return options.webhookSecret; | ||
| } | ||
|
|
||
| if (source === 'webhook') { | ||
| const res = await ctx.keys.get_webhook_signature(); | ||
| return res ?? ''; | ||
| } | ||
|
|
||
| if (source === 'endpoint' && options.key) { | ||
| return options.key; | ||
| } | ||
|
|
||
| if (source === 'endpoint' && ctx.authType === 'api_key') { | ||
| const res = await ctx.keys.get_api_key(); | ||
| return res ?? ''; | ||
| } | ||
|
|
||
| if (source === 'endpoint' && ctx.authType === 'oauth_2') { | ||
| const res = await ctx.keys.get_access_token(); | ||
| return res ?? ''; | ||
| } | ||
|
|
||
| return ''; | ||
| }, | ||
| } satisfies InternalConvoloAiPlugin; | ||
| } | ||
|
|
||
| export type { | ||
| ExampleEvent, | ||
| ConvoloAiWebhookOutputs, | ||
| } from './webhooks/types'; | ||
|
|
||
| export type { | ||
| ConvoloAiEndpointInputs, | ||
| ConvoloAiEndpointOutputs, | ||
| ExampleGetInput, | ||
| ExampleGetResponse, | ||
| } from './endpoints/types'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
🧩 Analysis chain
🌐 Web query:
Find the official ConvoloAI API documentation. Identify the production API base URL, supported regions, and required API version prefix.💡 Result:
Convolo.ai has rebranded to Brightcall, and its official website now redirects to brightcall.ai [1]. There is no publicly available, standalone "official ConvoloAI API documentation" [2][1]. Integration with Convolo.ai/Brightcall is primarily facilitated through third-party platforms and integration services (such as Composio, viaSocket, and direct webhook/API configurations within the platform) rather than a public, open-access API documentation portal [3][4][5][1]. Because there is no public-facing API documentation, there is no verified production API base URL, supported regions list, or required API version prefix available [2][1]. For developers or organizations seeking to use the platform's API, it is recommended to log in to the application at app.convolo.ai or visit brightcall.ai to access account-specific integration settings, API keys, or developer support provided to existing customers [1].
Citations:
🏁 Script executed:
Repository: corsairdev/corsair
Length of output: 49529
🌐 Web query:
Search official Brightcall or Convolo.ai developer documentation for the API base URL, API version, and authentication requirements.💡 Result:
Brightcall (formerly Convolo.ai) documentation provides specific guidelines for API interaction, though it does not utilize a single, unified global base URL [1][2][3]. API Base URLs: There is no singular base URL for the Brightcall/Convolo.ai API; rather, URLs are often project-specific or endpoint-specific [2][4]. Examples of documented endpoints include: - https://api.ipmaxi.leadcm.com/api/v2/projects [2] - https://app.convolo.ai/rest/v1/ext/add_call_api/ [3][5] API Versions: The API utilizes versioned endpoints, with documented versions including v1 and v2 (e.g., /api/v1/ and /api/v2/) [2][3]. Authentication Requirements: Authentication is handled via an API Key [2][5][6]. - Obtaining the Key: Users can generate or retrieve their API Key by navigating to the Widgets page in the Brightcall/Convolo.ai dashboard, selecting a widget, and accessing the Integrations tab [7]. - Implementation: The API key must be included in requests, typically as an api-key query parameter (e.g.,?api-key=YOUR_API_KEY) [2] or as a required parameter alongside a widget_key [5]. It is recommended that developers consult the official Brightcall Help Center for Developers for project-specific endpoint URLs and implementation details [1].
Citations:
🏁 Script executed:
Repository: corsairdev/corsair
Length of output: 50374
🌐 Web query:
Open the Brightcall Help Center developer articles and determine whether they specify one global API base URL or endpoint-specific URLs, including the exact documented URL examples.💡 Result:
The Brightcall Help Center developer articles do not specify a single global API base URL for all operations; instead, they document both project-specific endpoints and general service endpoints depending on the integration type [1][2]. For specific actions like making calls or adding contacts to a project, the documentation indicates the use of unique, auto-generated URLs [2]. For example, the developer guide for making calls via an API request provides a base-style structure for a general endpoint [1]: https://app.brightcall.ai/rest/v1/ext/add_call_api/?widget_key={WIDGET_KEY}&api_key={API_KEY}&lc_number={number} In contrast, for contact management and other project-level integrations, users are directed to copy a unique API request URL that is generated specifically for their project within the Brightcall Dashboard [2]. Consequently, there is no single global base URL, as the integration method determines whether a standardized endpoint or a unique, project-specific URL is used [1][2].
Citations:
🏁 Script executed:
Repository: corsairdev/corsair
Length of output: 15308
🌐 Web query:
Search the official Brightcall Help Center for the authentication parameter name and exact request format for the documented add-call API endpoint.💡 Result:
According to the official Brightcall Help Center, the add-call API endpoint (documented as "Making calls through an API request") requires two specific authentication parameters: widget_key and api_key [1]. The request can be submitted using either a GET or POST method [1]. GET Request Format: The parameters are passed as query parameters in the URL: https://app.brightcall.ai/rest/v1/ext/add_call_api/?widget_key={WIDGET_KEY}&api_key={API_KEY}&lc_number={number} [1] POST Request Format: The request must include a Content-Type of application/json, with the authentication keys and the lead's phone number in the JSON body [1]: { "widget_key": "%WIDGET_KEY%", "api_key": "%API_KEY%", "lc_number": "+1234567890" } [1] You may also include optional custom parameters (e.g., lc_param_name, lc_param_email) in the JSON body as needed [1].
Citations:
Replace the placeholder transport configuration before release.
CONVOLOAI_API_BASEishttps://api.example.com, so requests cannot reach Brightcall. Brightcall uses endpoint-specific URLs, such ashttps://app.brightcall.ai/rest/v1/ext/add_call_api/, and requireswidget_keyandapi_keyin the query or request body. Configure each endpoint with its documented URL and authentication format;TOKENcurrently sendsAuthorization: Bearer <apiKey>.🤖 Prompt for AI Agents