import { API_BASE_URL } from './apiBase' export type DashboardResponse = { metrics: { voice_calls: number messages_sent: number delivery_rate: number api_requests: number balance: number } activity: Array<{ id: string type: string title: string detail: string status: string occurred_at: string }> } export async function getDashboard(signal?: AbortSignal): Promise { const response = await fetch(`${API_BASE_URL}/api/v1/dashboard`, { signal, credentials: 'include', }) if (!response.ok) throw new Error(`Dashboard request failed: ${response.status}`) return response.json() as Promise } export type AuthUser = { id: string email: string name: string avatar_url: string | null email_verified: boolean has_password: boolean providers: string[] } async function authRequest(path: string, init?: RequestInit): Promise { const response = await fetch(`${API_BASE_URL}/api/v1/auth${path}`, { ...init, credentials: 'include', headers: { 'Content-Type': 'application/json', ...init?.headers }, }) if (!response.ok) { const body = await response.json().catch(() => null) throw new Error(body?.detail ?? 'Authentication request failed') } return response.json() as Promise } export const authApi = { me: () => authRequest('/me'), login: (email: string, password: string) => authRequest('/login', { method: 'POST', body: JSON.stringify({ email, password }) }), register: (name: string, email: string, password: string) => authRequest('/register', { method: 'POST', body: JSON.stringify({ name, email, password }) }), setPassword: (password: string, currentPassword?: string) => authRequest('/password', { method: 'POST', body: JSON.stringify({ password, current_password: currentPassword || null }), }), logout: () => fetch(`${API_BASE_URL}/api/v1/auth/logout`, { method: 'POST', credentials: 'include' }), googleUrl: `${API_BASE_URL}/api/v1/auth/google/start`, } export type KycDocument = { id: string document_type: string original_filename: string | null status: 'missing' | 'pending' | 'approved' | 'rejected' review_note: string | null uploaded_at: string | null reviewed_at: string | null } export type KycApplication = { id: string pan_number: string | null gst_number: string | null status: string completed: boolean submitted_at: string | null approved_at: string | null documents: KycDocument[] } export type DltDocument = { id: string document_type: string original_filename: string | null status: 'missing' | 'pending' | 'approved' | 'rejected' review_note: string | null uploaded_at: string | null reviewed_at: string | null } export type DltApplication = { id: string status: string completed: boolean submitted_at: string | null approved_at: string | null pe_tm_chain_binding_id: string documents: DltDocument[] } export type ComplianceStatus = { kyc_completed: boolean dlt_completed: boolean console_unlocked: boolean } async function jsonRequest(path: string, init?: RequestInit): Promise { const response = await fetch(`${API_BASE_URL}${path}`, { ...init, credentials: 'include', headers: init?.body instanceof FormData ? init.headers : { 'Content-Type': 'application/json', ...init?.headers }, }) if (!response.ok) { const body = await response.json().catch(() => null) throw new Error(typeof body?.detail === 'string' ? body.detail : 'Request failed') } if (response.status === 204) return undefined as T return response.json() as Promise } export const kycApi = { me: () => jsonRequest('/api/v1/kyc/me'), update: (pan_number: string, gst_number: string) => jsonRequest('/api/v1/kyc/me', { method: 'PUT', body: JSON.stringify({ pan_number, gst_number }) }), upload: (documentType: string, file: File) => { const body = new FormData() body.append('file', file) return jsonRequest(`/api/v1/kyc/documents/${documentType}`, { method: 'POST', body }) }, submit: () => jsonRequest('/api/v1/kyc/submit', { method: 'POST' }), templateUrl: `${API_BASE_URL}/api/v1/kyc/template`, } export const dltApi = { me: () => jsonRequest('/api/v1/dlt/me'), loaUrl: `${API_BASE_URL}/api/v1/dlt/loa`, upload: (documentType: string, file: File) => { const body = new FormData() body.append('file', file) return jsonRequest(`/api/v1/dlt/documents/${documentType}`, { method: 'POST', body }) }, confirmChainBinding: () => jsonRequest('/api/v1/dlt/chain-binding/confirm', { method: 'POST' }), submit: () => jsonRequest('/api/v1/dlt/submit', { method: 'POST' }), } export const complianceApi = { status: () => jsonRequest('/api/v1/compliance/status'), } export type AdminKycApplication = KycApplication & { user: { id: string; name: string; email: string } } export type AdminDltApplication = DltApplication & { user: { id: string; name: string; email: string } } export type SenderConfig = { id: string sender_id: string sender_type: 'promotional' | 'transactional' purpose: string dlt_entity_id: string status: 'pending' | 'approved' | 'rejected' review_note: string | null created_at: string reviewed_at: string | null } export type AdminSenderConfig = SenderConfig & { user: { id: string; name: string; email: string } } export type TemplateConfig = { id: string sender_config_id: string sender_id: string template_name: string template_text: string dlt_template_id: string status: 'pending' | 'approved' | 'rejected' review_note: string | null created_at: string reviewed_at: string | null } export const messagingApi = { listSenders: () => jsonRequest('/api/v1/messaging/senders'), createSender: (payload: { sender_id: string sender_type: string purpose: string dlt_entity_id: string }) => jsonRequest('/api/v1/messaging/senders', { method: 'POST', body: JSON.stringify(payload) }), listTemplates: () => jsonRequest('/api/v1/messaging/templates'), createTemplate: (payload: { sender_config_id: string template_name: string template_text: string dlt_template_id: string }) => jsonRequest('/api/v1/messaging/templates', { method: 'POST', body: JSON.stringify(payload) }), send: (payload: { sender_config_id: string template_id: string numbers: string message: string campaign_name?: string | null }) => jsonRequest('/api/v1/messaging/send', { method: 'POST', body: JSON.stringify(payload) }), } export type CampaignRunMode = 'manual' | 'on_upload' | 'scheduled' export type CampaignCsvUpload = { id: string original_filename: string total_rows: number status: 'validated' | 'running' | 'completed' | 'failed' run_started_at: string | null run_completed_at: string | null created_at: string } export type Campaign = { id: string name: string sender_config_id: string sender_id: string sender_type: 'promotional' | 'transactional' template_id: string template_name: string template_text: string number_column: string variable_columns: string[] run_mode: CampaignRunMode scheduled_at: string | null status: string created_at: string updated_at: string csv_upload_count: number csv_uploads: CampaignCsvUpload[] } export const campaignsApi = { list: () => jsonRequest('/api/v1/campaigns'), get: (campaignId: string) => jsonRequest(`/api/v1/campaigns/${campaignId}`), create: (payload: { name: string sender_config_id: string template_id: string number_column: string variable_columns: string[] run_mode: CampaignRunMode scheduled_at?: string | null }) => jsonRequest('/api/v1/campaigns', { method: 'POST', body: JSON.stringify(payload) }), listCsvUploads: (campaignId: string) => jsonRequest(`/api/v1/campaigns/${campaignId}/csv`), uploadCsv: (campaignId: string, file: File) => { const body = new FormData() body.append('file', file) return jsonRequest(`/api/v1/campaigns/${campaignId}/csv`, { method: 'POST', body }) }, runAutomation: (campaignId: string) => jsonRequest<{ processed_uploads: number; note: string }>(`/api/v1/campaigns/${campaignId}/run`, { method: 'POST' }), runCsv: (campaignId: string, uploadId: string) => jsonRequest( `/api/v1/campaigns/${campaignId}/csv/${uploadId}/run`, { method: 'POST' }, ), } export type ComposeSendResultItem = { to: string success: boolean job_id: string | null message_id: string | null error: string | null } export type ComposeSendResponse = { success: boolean campaign_name: string | null sent: number failed: number sender_id: string template_id: string template_name: string dlt_template_id: string results: ComposeSendResultItem[] } export type ApiKey = { id: string name: string key_prefix: string created_at: string last_used_at: string | null revoked_at: string | null status: 'active' | 'revoked' } export type ApiKeyWithToken = ApiKey & { token: string } export const apiKeysApi = { list: () => jsonRequest('/api/v1/api-keys'), create: (name: string) => jsonRequest('/api/v1/api-keys', { method: 'POST', body: JSON.stringify({ name }) }), regenerate: (keyId: string) => jsonRequest(`/api/v1/api-keys/${keyId}/regenerate`, { method: 'POST' }), revoke: (keyId: string) => fetch(`${API_BASE_URL}/api/v1/api-keys/${keyId}`, { method: 'DELETE', credentials: 'include' }).then((response) => { if (!response.ok) throw new Error('Unable to revoke API key') }), } export type MessageApiDoc = { id: string method: string path: string title: string summary: string authentication: { type: string header: string format: string alternate_header: string } request_body: Record responses: Record }> } export type SendMessageResponse = { success: boolean job_id: string | null message_id: string | null to: string | null sender_id: string template_id: string template_name: string dlt_template_id: string } export const messagesApi = { docs: () => jsonRequest('/api/v1/messages/docs/send'), send: (apiKey: string, payload: { sender_id: string template_id: string to: string message: string }) => fetch(`${API_BASE_URL}/api/v1/messages/send`, { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${apiKey}`, }, body: JSON.stringify(payload), }).then(async (response) => { const body = await response.json().catch(() => null) if (!response.ok) { throw new Error(typeof body?.detail === 'string' ? body.detail : 'SMS send request failed') } return body as SendMessageResponse }), } export type UrmiOtpProject = { id: string project_name: string message_label: string app_type: 'web' | 'mobile' app_url: string purpose: string status: 'pending' | 'approved' | 'rejected' review_note: string | null terms_accepted_at: string created_at: string reviewed_at: string | null } export type OtpTemplateDefinition = { type: string name: string content: string sample: string uses: string[] variables: string[] } export type UrmiOtpDocumentation = { project: UrmiOtpProject templates: OtpTemplateDefinition[] api: { method: string path: string implemented: boolean summary: string parameters: Record example: Record } } export type AdminUrmiOtpProject = UrmiOtpProject & { user: { id: string; name: string; email: string } } export const urmiOtpApi = { listProjects: () => jsonRequest('/api/v1/urmiotp/projects'), createProject: (payload: { project_name: string message_label: string app_type: 'web' | 'mobile' app_url: string purpose: string terms_accepted: boolean }) => jsonRequest('/api/v1/urmiotp/projects', { method: 'POST', body: JSON.stringify(payload), }), documentation: (projectId: string) => jsonRequest(`/api/v1/urmiotp/projects/${projectId}/documentation`), generate: (payload: { project_name: string template_type: string to: string variables: { otp: string; validity_minutes: string } }) => jsonRequest<{ success: boolean log_id: string project_name: string template_type: string to: string message_preview: string status: string }>('/api/v1/urmiotp/generate', { method: 'POST', body: JSON.stringify(payload), }), } export type PhoneNumber = { id: string phone_number: string monthly_number_price: number inbound_price: number outbound_price: number currency: string status: 'available' | 'assigned' acquisition_type: 'admin_assigned' | 'purchased' | null assigned_at: string | null created_at: string } export type IntegrationEndpoint = { id: string name: string phone_number_id: string phone_number: string url: string enabled: boolean created_at: string updated_at: string signing_secret?: string } export type VoiceSocketEndpoint = IntegrationEndpoint export type SmsDeliveryWebhook = IntegrationEndpoint & { description: string | null event: 'message.delivery.updated' } export type IntegrationsDocs = { title: string summary: string relay: { principle: string latency: string } socket: { title: string description: string events: string[] authentication: { headers: string[] signature: string replay_protection: string } } webhook: { title: string description: string event: string statuses: string[] authentication: { headers: string[] signature: string } example: Record } api_authentication: { header: string format: string note: string } endpoints: Array<{ method: string; path: string; description: string }> } type EndpointPayload = { name: string phone_number_id: string url: string description?: string | null enabled?: boolean } export const integrationsApi = { docs: () => jsonRequest('/api/v1/integrations/docs'), listSockets: () => jsonRequest('/api/v1/integrations/sockets'), createSocket: (payload: EndpointPayload) => jsonRequest('/api/v1/integrations/sockets', { method: 'POST', body: JSON.stringify(payload), }), updateSocket: (id: string, payload: Partial) => jsonRequest(`/api/v1/integrations/sockets/${id}`, { method: 'PATCH', body: JSON.stringify(payload), }), deleteSocket: (id: string) => jsonRequest(`/api/v1/integrations/sockets/${id}`, { method: 'DELETE' }), listWebhooks: () => jsonRequest('/api/v1/integrations/webhooks'), createWebhook: (payload: EndpointPayload) => jsonRequest('/api/v1/integrations/webhooks', { method: 'POST', body: JSON.stringify(payload), }), updateWebhook: (id: string, payload: Partial) => jsonRequest(`/api/v1/integrations/webhooks/${id}`, { method: 'PATCH', body: JSON.stringify(payload), }), deleteWebhook: (id: string) => jsonRequest(`/api/v1/integrations/webhooks/${id}`, { method: 'DELETE' }), testWebhook: (id: string) => jsonRequest<{ delivered: boolean; response_code: number }>( `/api/v1/integrations/webhooks/${id}/test`, { method: 'POST' }, ), } export type VoiceCall = { id: string direction: string from: string to: string status: string stream_id: string | null call_id: string | null bridge_mode: string upstream: string | null error_message: string | null answered_at: string | null ended_at: string | null created_at: string media_url?: string } export type VoiceApiDocs = { title: string summary: string method: string path: string authentication: { header: string format: string alternate_header?: string } request_body: Record response_example: Record relay: { principle: string latency: string } outbound_flow: string[] endpoints: Array<{ method: string; path: string; description: string }> } export const voiceApi = { docs: () => jsonRequest('/api/v1/voice/docs'), createCall: (payload: { to: string; from: string; bridge_mode?: 'console' | 'upstream'; upstream?: string }) => jsonRequest('/api/v1/voice/calls', { method: 'POST', body: JSON.stringify(payload) }), getCall: (callId: string) => jsonRequest(`/api/v1/voice/calls/${callId}`), createCallWithApiKey: ( apiKey: string, payload: { to: string; from: string; bridge_mode?: 'console' | 'upstream'; upstream?: string }, ) => fetch(`${API_BASE_URL}/api/v1/voice/calls`, { method: 'POST', credentials: 'include', headers: { Authorization: `Bearer ${apiKey}`, 'Content-Type': 'application/json', }, body: JSON.stringify(payload), }).then(async (response) => { if (!response.ok) { const body = await response.json().catch(() => null) throw new Error(typeof body?.detail === 'string' ? body.detail : 'Request failed') } return response.json() as Promise }), } export type AdminPhoneNumber = PhoneNumber & { user: { id: string; name: string; email: string } | null } export const numbersApi = { catalog: () => jsonRequest('/api/v1/numbers/catalog'), mine: () => jsonRequest('/api/v1/numbers/mine'), purchase: (numberId: string) => jsonRequest(`/api/v1/numbers/${numberId}/purchase`, { method: 'POST' }), } export type AdminTemplateConfig = TemplateConfig & { user: { id: string; name: string; email: string } } export const adminApi = { me: () => jsonRequest<{ username: string }>('/api/v1/admin/me'), login: (username: string, password: string) => jsonRequest<{ username: string }>('/api/v1/admin/login', { method: 'POST', body: JSON.stringify({ username, password }), }), logout: () => fetch(`${API_BASE_URL}/api/v1/admin/logout`, { method: 'POST', credentials: 'include' }), listKyc: () => jsonRequest('/api/v1/admin/compliance/kyc'), reviewDocument: (applicationId: string, documentId: string, status: 'approved' | 'rejected', review_note?: string) => jsonRequest(`/api/v1/admin/compliance/kyc/${applicationId}/documents/${documentId}`, { method: 'PATCH', body: JSON.stringify({ status, review_note: review_note || null }), }), listDlt: () => jsonRequest('/api/v1/admin/compliance/dlt'), reviewDltDocument: (applicationId: string, documentId: string, status: 'approved' | 'rejected', review_note?: string) => jsonRequest(`/api/v1/admin/compliance/dlt/${applicationId}/documents/${documentId}`, { method: 'PATCH', body: JSON.stringify({ status, review_note: review_note || null }), }), listSenders: () => jsonRequest('/api/v1/admin/compliance/senders'), reviewSender: (senderId: string, status: 'approved' | 'rejected', review_note?: string) => jsonRequest(`/api/v1/admin/compliance/senders/${senderId}`, { method: 'PATCH', body: JSON.stringify({ status, review_note: review_note || null }), }), listTemplates: () => jsonRequest('/api/v1/admin/compliance/templates'), reviewTemplate: (templateId: string, status: 'approved' | 'rejected', review_note?: string) => jsonRequest(`/api/v1/admin/compliance/templates/${templateId}`, { method: 'PATCH', body: JSON.stringify({ status, review_note: review_note || null }), }), listUrmiOtpProjects: () => jsonRequest('/api/v1/admin/compliance/urmiotp-projects'), reviewUrmiOtpProject: (projectId: string, status: 'approved' | 'rejected', review_note?: string) => jsonRequest(`/api/v1/admin/compliance/urmiotp-projects/${projectId}`, { method: 'PATCH', body: JSON.stringify({ status, review_note: review_note || null }), }), listPhoneNumbers: () => jsonRequest('/api/v1/admin/phone-numbers'), createPhoneNumber: (payload: { phone_number: string monthly_number_price: number inbound_price: number outbound_price: number user_email?: string | null }) => jsonRequest('/api/v1/admin/phone-numbers', { method: 'POST', body: JSON.stringify(payload), }), updatePhoneNumber: (numberId: string, payload: { monthly_number_price?: number inbound_price?: number outbound_price?: number user_email?: string | null release?: boolean }) => jsonRequest(`/api/v1/admin/phone-numbers/${numberId}`, { method: 'PATCH', body: JSON.stringify(payload), }), } export type LogType = 'outbound' | 'inbound' | 'sms' | 'otp' export type LogEntry = { id: string from?: string to?: string template?: string otp_type?: string project?: string socket_name?: string status?: string time: string } export type LogsResponse = { type: LogType page: number page_size: number total: number total_pages: number from: string to: string items: LogEntry[] } export const logsApi = { list: (params: { type: LogType; from: string; to: string; page?: number }) => { const query = new URLSearchParams({ type: params.type, from: params.from, to: params.to, page: String(params.page ?? 1), }) return jsonRequest(`/api/v1/logs?${query.toString()}`) }, } export type AnalyticsPeriod = 'weekly' | 'monthly' | 'quarterly' export type AnalyticsService = 'sms' | 'inbound' | 'outbound' | 'otp' export type AnalyticsGroupBy = 'dlt_sender' | 'dlt_template' | 'did' | 'socket' | 'project' | 'otp_type' export type UsageAnalytics = { period: AnalyticsPeriod service: AnalyticsService group_by: AnalyticsGroupBy from: string to: string totals: { sms: number inbound: number outbound: number otp: number } timeline: Array<{ label: string period_start: string sms: number inbound: number outbound: number otp: number }> breakdown: Array<{ label: string detail: string count: number }> } export const analyticsApi = { usage: (params: { period: AnalyticsPeriod; service: AnalyticsService; group_by: AnalyticsGroupBy }) => { const query = new URLSearchParams({ period: params.period, service: params.service, group_by: params.group_by, }) return jsonRequest(`/api/v1/analytics/usage?${query.toString()}`) }, } export type WhatsAppSetup = { webhook_url: string verify_token_configured: boolean app_secret_configured: boolean access_token_configured: boolean phone_number_id: string | null business_account_id: string | null meta_app_id: string | null api_version: string recommended_fields: string[] docs_url: string } export type WhatsAppWebhookEvent = { id: string waba_id: string | null phone_number_id: string | null field: string event_type: string from_wa_id: string | null message_id: string | null status: string | null created_at: string } export const whatsappApi = { setup: () => jsonRequest('/api/v1/whatsapp/setup'), events: () => jsonRequest('/api/v1/whatsapp/events'), sendText: (payload: { to: string; body: string }) => jsonRequest>('/api/v1/whatsapp/messages/send', { method: 'POST', body: JSON.stringify(payload), }), }