@kasuvia/sdk 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +112 -0
  3. package/dist/index.d.mts +1891 -0
  4. package/dist/index.d.ts +1891 -0
  5. package/dist/index.js +3540 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/index.mjs +3314 -0
  8. package/dist/index.mjs.map +1 -0
  9. package/package.json +59 -0
  10. package/src/client/authClient.ts +135 -0
  11. package/src/client/graphqlClient.ts +53 -0
  12. package/src/client/httpClient.ts +298 -0
  13. package/src/config/index.ts +102 -0
  14. package/src/graphql/collections.graphql.ts +56 -0
  15. package/src/graphql/index.ts +7 -0
  16. package/src/graphql/products.graphql.ts +710 -0
  17. package/src/graphql/wishlist.graphql.ts +33 -0
  18. package/src/hooks/index.ts +26 -0
  19. package/src/hooks/use-auth.ts +182 -0
  20. package/src/hooks/use-bespoke-availability.ts +20 -0
  21. package/src/hooks/use-cart.ts +207 -0
  22. package/src/hooks/use-cms.ts +165 -0
  23. package/src/hooks/use-collections.ts +40 -0
  24. package/src/hooks/use-consultation-stream.ts +141 -0
  25. package/src/hooks/use-consultations.ts +76 -0
  26. package/src/hooks/use-countries.ts +24 -0
  27. package/src/hooks/use-currencies.ts +27 -0
  28. package/src/hooks/use-google-translate.ts +164 -0
  29. package/src/hooks/use-is-mounted.ts +9 -0
  30. package/src/hooks/use-languages.ts +33 -0
  31. package/src/hooks/use-order-stream.ts +195 -0
  32. package/src/hooks/use-orders.ts +64 -0
  33. package/src/hooks/use-payment.ts +68 -0
  34. package/src/hooks/use-products.ts +113 -0
  35. package/src/hooks/use-service-booking.ts +118 -0
  36. package/src/hooks/use-states.ts +28 -0
  37. package/src/hooks/use-wishlist.ts +121 -0
  38. package/src/index.ts +65 -0
  39. package/src/services/app.service.ts +17 -0
  40. package/src/services/auth.service.ts +332 -0
  41. package/src/services/bespoke.service.ts +17 -0
  42. package/src/services/cart.service.ts +245 -0
  43. package/src/services/cms.service.ts +112 -0
  44. package/src/services/collection.service.ts +77 -0
  45. package/src/services/config.service.ts +42 -0
  46. package/src/services/consultation.service.ts +51 -0
  47. package/src/services/index.ts +21 -0
  48. package/src/services/logistics.service.ts +95 -0
  49. package/src/services/notifications.service.ts +50 -0
  50. package/src/services/order.service.ts +169 -0
  51. package/src/services/payment.service.ts +127 -0
  52. package/src/services/product.service.ts +678 -0
  53. package/src/services/service-booking.service.ts +86 -0
  54. package/src/services/wishlist.service.ts +84 -0
  55. package/src/types/auth/index.ts +126 -0
  56. package/src/types/bespoke/index.ts +39 -0
  57. package/src/types/business/index.ts +6 -0
  58. package/src/types/cms/index.ts +77 -0
  59. package/src/types/consultations/index.ts +79 -0
  60. package/src/types/index.ts +27 -0
  61. package/src/types/media/index.ts +41 -0
  62. package/src/types/payments/index.ts +120 -0
  63. package/src/types/services/index.ts +80 -0
  64. package/src/types/store/index.ts +282 -0
  65. package/src/types/store/shipping.ts +38 -0
  66. package/src/types/ui/index.ts +32 -0
  67. package/src/utils/cache.ts +33 -0
  68. package/src/utils/checkout.ts +39 -0
  69. package/src/utils/customer.ts +20 -0
  70. package/src/utils/error-handler.ts +14 -0
  71. package/src/utils/index.ts +10 -0
  72. package/src/utils/logger.ts +79 -0
  73. package/src/utils/sanitize-url.ts +55 -0
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Service Booking Service
3
+ *
4
+ * Handles service appointments and deliverables.
5
+ */
6
+ import { storeManagementAxios } from '../client/httpClient'
7
+ import type {
8
+ ServiceAppointment,
9
+ ServiceAppointmentCreatePayload,
10
+ AvailableSlot,
11
+ ServiceDeliverable,
12
+ DeliverableApprovalPayload,
13
+ } from '../types/services'
14
+
15
+ export async function getAvailableSlots(
16
+ product_id: string,
17
+ date_from: string,
18
+ date_to: string
19
+ ): Promise<AvailableSlot[]> {
20
+ const { data } = await storeManagementAxios.get<AvailableSlot[]>(
21
+ `service/available-slots/${product_id}`,
22
+ { params: { date_from, date_to } }
23
+ )
24
+ return data
25
+ }
26
+
27
+ export async function bookAppointment(
28
+ payload: ServiceAppointmentCreatePayload
29
+ ): Promise<ServiceAppointment> {
30
+ const { data } = await storeManagementAxios.post<ServiceAppointment>('service/appointments/', payload)
31
+ return data
32
+ }
33
+
34
+ export async function getAppointments(): Promise<ServiceAppointment[]> {
35
+ const { data } = await storeManagementAxios.get<ServiceAppointment[]>('service/bookings/my')
36
+ return data
37
+ }
38
+
39
+ export async function getAppointment(id: string): Promise<ServiceAppointment> {
40
+ const { data } = await storeManagementAxios.get<ServiceAppointment>(`service/bookings/${id}`)
41
+ return data
42
+ }
43
+
44
+ export async function cancelAppointment(id: string): Promise<void> {
45
+ await storeManagementAxios.delete(`service/bookings/${id}`)
46
+ }
47
+
48
+ export async function getDeliverables(order_id: string): Promise<ServiceDeliverable[]> {
49
+ const { data } = await storeManagementAxios.get<ServiceDeliverable[]>(`service/projects/${order_id}/deliverables/`)
50
+ return data
51
+ }
52
+
53
+ export async function approveDeliverable(
54
+ order_id: string,
55
+ deliverable_id: string
56
+ ): Promise<ServiceDeliverable> {
57
+ const { data } = await storeManagementAxios.post<ServiceDeliverable>(
58
+ `service/projects/${order_id}/deliverables/${deliverable_id}/approve`,
59
+ { approved: true }
60
+ )
61
+ return data
62
+ }
63
+
64
+ export async function requestRevision(
65
+ order_id: string,
66
+ deliverable_id: string,
67
+ feedback: string
68
+ ): Promise<ServiceDeliverable> {
69
+ const { data } = await storeManagementAxios.post<ServiceDeliverable>(
70
+ `service/projects/${order_id}/deliverables/${deliverable_id}/revision`,
71
+ { approved: false, feedback }
72
+ )
73
+ return data
74
+ }
75
+
76
+ // Service object export for backward compatibility
77
+ export const serviceBookingService = {
78
+ getAvailableSlots,
79
+ bookAppointment,
80
+ getAppointments,
81
+ getAppointment,
82
+ cancelAppointment,
83
+ getDeliverables,
84
+ approveDeliverable,
85
+ requestRevision,
86
+ }
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Wishlist Service
3
+ *
4
+ * Handles wishlist operations.
5
+ */
6
+ import { storeManagementAxios } from '../client/httpClient'
7
+ import { getGraphQLClient } from '../client/graphqlClient'
8
+ import type { WishlistItem, WishlistListResponse, WishlistCheckResponse } from '../types/store'
9
+
10
+ const GET_WISHLIST = `
11
+ query GetWishlist($page: Int!, $pageSize: Int!) {
12
+ wishlist(page: $page, pageSize: $pageSize) {
13
+ items {
14
+ id
15
+ product_id
16
+ notes
17
+ created_at
18
+ product_name
19
+ product_slug
20
+ product_price
21
+ product_image
22
+ }
23
+ total
24
+ page
25
+ page_size
26
+ total_pages
27
+ }
28
+ }
29
+ `
30
+
31
+ const CHECK_IN_WISHLIST = `
32
+ query CheckInWishlist($productId: String!) {
33
+ check_in_wishlist(productId: $productId) {
34
+ in_wishlist
35
+ }
36
+ }
37
+ `
38
+
39
+ /**
40
+ * Fetch the customer's wishlist for the current business.
41
+ */
42
+ export async function getWishlist(params?: { page?: number; pageSize?: number }): Promise<WishlistListResponse> {
43
+ const client = getGraphQLClient()
44
+ const variables = {
45
+ page: params?.page || 1,
46
+ pageSize: params?.pageSize || 20,
47
+ }
48
+ const data = await client.request(GET_WISHLIST, variables)
49
+ return data.wishlist
50
+ }
51
+
52
+ /**
53
+ * Check if a product is in the customer's wishlist.
54
+ */
55
+ export async function checkInWishlist(productId: string): Promise<WishlistCheckResponse> {
56
+ const client = getGraphQLClient()
57
+ const data = await client.request(CHECK_IN_WISHLIST, { productId })
58
+ return data.check_in_wishlist
59
+ }
60
+
61
+ /**
62
+ * Add a product to the customer's wishlist.
63
+ */
64
+ export async function addToWishlist(productId: string, notes?: string): Promise<WishlistItem> {
65
+ const { data } = await storeManagementAxios.post<WishlistItem>("wishlist/", {
66
+ product_id: productId,
67
+ notes: notes || undefined,
68
+ })
69
+ return data
70
+ }
71
+
72
+ /**
73
+ * Remove an item from the customer's wishlist by item ID.
74
+ */
75
+ export async function removeFromWishlist(itemId: string): Promise<void> {
76
+ await storeManagementAxios.delete(`wishlist/${itemId}`)
77
+ }
78
+
79
+ /**
80
+ * Remove a product from the customer's wishlist by product ID.
81
+ */
82
+ export async function removeProductFromWishlist(productId: string): Promise<void> {
83
+ await storeManagementAxios.delete(`wishlist/product/${productId}`)
84
+ }
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Simplified customer auth types for luxe-storefront.
3
+ * Customers only need enough to track their orders — no RBAC, MFA, or complex profiles.
4
+ */
5
+
6
+ // ── Customer Identity ─────────────────────────────────────────────────────────
7
+
8
+ /**
9
+ * Media System response object for avatar/profile picture.
10
+ * Stored as JSON in the backend Profile model.
11
+ */
12
+ export interface AvatarObject {
13
+ id: string;
14
+ alt: string;
15
+ url: string;
16
+ }
17
+
18
+ export interface CustomerProfileFields {
19
+ firstname: string;
20
+ lastname: string;
21
+ phone: string;
22
+ }
23
+
24
+ export interface CustomerUser {
25
+ id: string;
26
+ email: string;
27
+ firstname?: string;
28
+ lastname?: string;
29
+ phone?: string;
30
+ /** Derived display name — prefer firstname + lastname when available */
31
+ full_name?: string;
32
+ avatar: string | null;
33
+ provider: 'google' | 'facebook' | 'email';
34
+ }
35
+
36
+ /** GET/PUT /auth/profile/ — matches luxe-auth UserSerializer */
37
+ export interface AuthUserResponse {
38
+ id: string;
39
+ email: string;
40
+ is_google_auth_enabled?: boolean;
41
+ is_facebook_auth_enabled?: boolean;
42
+ profile?: {
43
+ firstname?: string;
44
+ lastname?: string;
45
+ phone?: string;
46
+ profile_picture?: string | null;
47
+ };
48
+ }
49
+
50
+ export interface UpdateProfilePayload {
51
+ firstname?: string;
52
+ lastname?: string;
53
+ phone?: string;
54
+ }
55
+
56
+ // ── Business Context (storefront is scoped to one business) ──────────────────
57
+
58
+ export interface BusinessContext {
59
+ id: string; // UUID
60
+ business_id: string; // B-XXXXXXXX — permanent, never changes
61
+ name: string;
62
+ logo_picture?: string | null;
63
+ display_currency?: string;
64
+ }
65
+
66
+ // ── API Responses ─────────────────────────────────────────────────────────────
67
+
68
+ export interface CustomerAuthResponse {
69
+ access: string;
70
+ refresh: string;
71
+ user: CustomerUser;
72
+ business: BusinessContext;
73
+ is_new?: boolean;
74
+ }
75
+
76
+ export interface RefreshTokenResponse {
77
+ access: string;
78
+ refresh?: string;
79
+ }
80
+
81
+ // ── Request Payloads ──────────────────────────────────────────────────────────
82
+
83
+ /** POST /auth/login/customer/ — field name is `tenant_id` (the business_id) */
84
+ export interface CustomerLoginPayload {
85
+ tenant_id: string; // config.api.storefrontBusinessId
86
+ email: string;
87
+ password: string;
88
+ }
89
+
90
+ /** POST /auth/register/customer/ */
91
+ export interface CustomerRegisterPayload {
92
+ tenant_id: string; // config.api.storefrontBusinessId
93
+ /** Full name — backend splits this into firstname and lastname on the Profile */
94
+ full_name: string;
95
+ email: string;
96
+ password: string;
97
+ }
98
+
99
+ /** POST /auth/verify-otp/ */
100
+ export interface OTPVerifyPayload {
101
+ email: string;
102
+ code: string;
103
+ purpose?: 'verify' | 'password_reset';
104
+ }
105
+
106
+ /** POST /auth/resend-otp/ */
107
+ export interface ResendOTPPayload {
108
+ email: string;
109
+ }
110
+
111
+ /** POST /auth/logout/ */
112
+ export interface LogoutPayload {
113
+ refresh?: string;
114
+ }
115
+
116
+ // ── Auth Context ──────────────────────────────────────────────────────────────
117
+
118
+ export interface AuthContextValue {
119
+ customer: CustomerUser | null;
120
+ isLoading: boolean;
121
+ isModalOpen: boolean;
122
+ openModal: () => void;
123
+ closeModal: () => void;
124
+ setCustomer: (user: CustomerUser | null) => void;
125
+ logout: () => Promise<void>;
126
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Bespoke slot booking types for customer-facing storefront
3
+ */
4
+
5
+ export type SlotBookingStatus = "reserved" | "confirmed" | "completed" | "voided";
6
+
7
+ export interface BespokeSlotBooking {
8
+ id: string;
9
+ product_id: string;
10
+ capacity_config_id: string | null;
11
+ consultation_id: string | null;
12
+ order_id: string | null;
13
+ customer_id: string;
14
+ status: SlotBookingStatus;
15
+ preferred_start_date: string | null;
16
+ preferred_end_date: string | null;
17
+ estimated_completion_date: string | null;
18
+ notes: string | null;
19
+ created_at: string;
20
+ updated_at: string;
21
+ }
22
+
23
+ export interface BespokeCapacityConfig {
24
+ id: string;
25
+ business_id: string;
26
+ product_id: string;
27
+ slot_period: "weekly" | "monthly" | "yearly";
28
+ total_slots: number;
29
+ slots_used: number;
30
+ period_start_date: string;
31
+ period_end_date: string;
32
+ production_days_per_order: number;
33
+ buffer_days_between_orders: number;
34
+ blocked_dates: string[];
35
+ auto_reset: boolean;
36
+ is_active: boolean;
37
+ created_at: string;
38
+ updated_at: string;
39
+ }
@@ -0,0 +1,6 @@
1
+ export interface BusinessConfig {
2
+ business_id: string;
3
+ store_name: string;
4
+ store_currency: string;
5
+ is_active: boolean;
6
+ }
@@ -0,0 +1,77 @@
1
+ /**
2
+ * CMS Types
3
+ *
4
+ * Types for kasuvia-cms integration - dynamic content models and entries
5
+ */
6
+
7
+ export interface CmsField {
8
+ name: string
9
+ label: string
10
+ type: string
11
+ required: boolean
12
+ config: Record<string, any>
13
+ sub_fields?: CmsField[]
14
+ }
15
+
16
+ export interface CmsModelPermissions {
17
+ read: boolean
18
+ create: boolean
19
+ update: boolean
20
+ delete: boolean
21
+ }
22
+
23
+ export interface CmsModelPublicApiPermissions {
24
+ public_api: CmsModelPermissions
25
+ }
26
+
27
+ export interface CmsModel {
28
+ id: string
29
+ business_id: string
30
+ model_slug: string
31
+ display_name: string
32
+ description: string | null
33
+ fields: CmsField[]
34
+ permissions: CmsModelPublicApiPermissions
35
+ }
36
+
37
+ export interface CmsEntry {
38
+ id: string
39
+ business_id: string
40
+ model_slug: string
41
+ data: Record<string, any>
42
+ created_at: string
43
+ updated_at: string
44
+ created_by: string | null
45
+ }
46
+
47
+ export interface CmsEntryListResponse {
48
+ entries: CmsEntry[]
49
+ total: number
50
+ page: number
51
+ page_size: number
52
+ }
53
+
54
+ export interface CmsIcon {
55
+ id: string
56
+ name: string
57
+ category: string
58
+ tags: string[]
59
+ }
60
+
61
+ export interface CmsIconListResponse {
62
+ icons: CmsIcon[]
63
+ total: number
64
+ }
65
+
66
+ export interface ListCmsEntriesParams {
67
+ page?: number
68
+ page_size?: number
69
+ }
70
+
71
+ export interface CreateCmsEntryParams {
72
+ data: Record<string, any>
73
+ }
74
+
75
+ export interface UpdateCmsEntryParams {
76
+ data: Record<string, any>
77
+ }
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Consultation types for customer-facing storefront
3
+ */
4
+
5
+ export type ConsultationStatus =
6
+ | "pending"
7
+ | "quoted"
8
+ | "negotiating"
9
+ | "deposit_pending"
10
+ | "deposit_paid"
11
+ | "converting"
12
+ | "converted"
13
+ | "rejected";
14
+
15
+ export type ConsultationProductType = "bespoke" | "service";
16
+
17
+ export interface ConsultationMessage {
18
+ id: string;
19
+ consultation_id: string;
20
+ sender_id: string;
21
+ sender_role: "customer" | "merchant" | "system";
22
+ message: string;
23
+ attachments: string[];
24
+ is_read: boolean;
25
+ created_at: string;
26
+ }
27
+
28
+ export interface Consultation {
29
+ id: string;
30
+ business_id: string;
31
+ customer_id: string;
32
+ product_id: string | null;
33
+ title: string;
34
+ status: ConsultationStatus;
35
+ product_type: ConsultationProductType;
36
+ quote_amount: number | null;
37
+ agreed_price: number | null;
38
+ deposit_amount: number | null;
39
+ deposit_required: boolean;
40
+ is_physical_delivery: boolean;
41
+ expected_delivery_type: string | null;
42
+ structured_details: Record<string, unknown>;
43
+ rejection_reason: string | null;
44
+ converted_order_id: string | null;
45
+ slot_booking_id: string | null;
46
+ capacity_config_id: string | null;
47
+ created_at: string;
48
+ updated_at: string;
49
+ messages: ConsultationMessage[];
50
+ }
51
+
52
+ export interface ConsultationCreatePayload {
53
+ product_id?: string;
54
+ title: string;
55
+ description: string;
56
+ reference_images?: string[];
57
+ custom_measurements?: Record<string, string | number>;
58
+ preferred_timeline?: string;
59
+ special_instructions?: string;
60
+ product_type?: ConsultationProductType;
61
+ }
62
+
63
+ export interface ConsultationMessagePayload {
64
+ message: string;
65
+ attachments?: string[];
66
+ }
67
+
68
+ export interface ConsultationQuoteAcceptPayload {
69
+ agreed_price: number;
70
+ }
71
+
72
+ export interface BespokeAvailability {
73
+ available_slots: number;
74
+ next_available_date: string | null;
75
+ period_end: string;
76
+ blocked_dates: string[];
77
+ production_days: number;
78
+ is_available: boolean;
79
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * SDK Types Barrel Export
3
+ *
4
+ * Central export point for all domain types.
5
+ * Organized by backend service:
6
+ * - auth: kasuvia-auth
7
+ * - store: kasuvia-store-management
8
+ * - payments: kasuvia-payment-system
9
+ * - cms: kasuvia-cms
10
+ * - media: kasuvia-media-system
11
+ * - consultations: kasuvia-store-management (consultations feature)
12
+ * - services: kasuvia-store-management (service booking feature)
13
+ * - bespoke: kasuvia-store-management (bespoke slot booking feature)
14
+ * - business: business configuration
15
+ * - ui: UI/app state types
16
+ */
17
+
18
+ export * from './auth'
19
+ export * from './store'
20
+ export * from './payments'
21
+ export * from './consultations'
22
+ export * from './services'
23
+ export * from './bespoke'
24
+ export * from './cms'
25
+ export * from './media'
26
+ export * from './business'
27
+ export * from './ui'
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Media types for the storefront
3
+ */
4
+
5
+ export interface MediaAsset {
6
+ id: string
7
+ url: string
8
+ filename: string
9
+ content_type: string
10
+ size: number
11
+ business_id: string
12
+ affiliation: string
13
+ created_at: string
14
+ alt?: string
15
+ description?: string
16
+ }
17
+
18
+ export interface MediaUploadParams {
19
+ business_id?: string
20
+ owner_id?: string
21
+ uploaded_by_name?: string
22
+ affiliation?: string
23
+ context: string // Required for security: describes the upload context (e.g., product, user, business)
24
+ entity_id: string // Required for security: ID of the entity this file belongs to
25
+ alt?: string
26
+ description?: string
27
+ idempotency_key?: string
28
+ }
29
+
30
+ export interface MediaAssetUpdatePayload {
31
+ alt?: string
32
+ description?: string
33
+ affiliation?: string
34
+ }
35
+
36
+ export interface StorageStats {
37
+ total_bytes: number
38
+ used_bytes: number
39
+ available_bytes: number
40
+ asset_count: number
41
+ }
@@ -0,0 +1,120 @@
1
+ /**
2
+ * @file types/payments/index.ts
3
+ * @description All customer-facing payment types for the Luxe Payment System.
4
+ *
5
+ * Auth model:
6
+ * - X-Storefront-Key → identifies the business storefront
7
+ * - X-Business-ID → tenant context
8
+ * No business-owner JWT used here — these are CUSTOMER-facing types.
9
+ *
10
+ * Payment flow:
11
+ * Customer → Business Owner : Monnify (NGN) | Flutterwave (non-NGN)
12
+ * Business Owner → Luxe : Subscription (separate, JWT-auth)
13
+ * Luxe → Business Owner : Payout (separate, JWT-auth)
14
+ */
15
+
16
+ // ── Configuration Types ─────────────────────────────────────────────────────────
17
+
18
+ export interface Currency {
19
+ code: string; // ISO 4217 currency code (e.g., USD, NGN, EUR)
20
+ name: string; // Full currency name (e.g., US Dollar, Nigerian Naira)
21
+ symbol: string; // Currency symbol (e.g., $, ₦, €)
22
+ decimals: number; // Number of decimal places (e.g., 2 for USD, 0 for JPY)
23
+ is_active: boolean; // Whether this currency is active
24
+ }
25
+
26
+ export interface SupportedCurrenciesResponse {
27
+ currencies: Currency[];
28
+ }
29
+
30
+ export interface BackendLanguage {
31
+ code: string; // Language code (e.g., en, ar, fr)
32
+ label: string; // Language label (e.g., English, Arabic, French)
33
+ flag: string; // Flag emoji or icon
34
+ }
35
+
36
+ export interface SupportedLang {
37
+ code: string; // Google Translate code
38
+ appCode: string; // Internal app code
39
+ label: string;
40
+ native: string;
41
+ flag: string;
42
+ }
43
+
44
+ export interface SupportedLanguagesResponse {
45
+ languages: BackendLanguage[];
46
+ }
47
+
48
+ // ── Request Types ─────────────────────────────────────────────────────────────
49
+
50
+ export interface DVACreateRequest {
51
+ order_id?: string;
52
+ amount: number;
53
+ customer_email: string;
54
+ customer_name?: string;
55
+ /** Defaults to NGN — DVA is Monnify-only */
56
+ currency?: string;
57
+ /** Idempotency key to prevent duplicate DVA creation */
58
+ idempotency_key?: string;
59
+ }
60
+
61
+ export interface PaymentInitiateRequest {
62
+ amount: number;
63
+ currency: string;
64
+ customer_email: string;
65
+ customer_name?: string;
66
+ order_id?: string;
67
+ quote_id?: string;
68
+ /** Window origin of the storefront — used as gateway redirect base URL */
69
+ storefront_origin?: string;
70
+ metadata?: Record<string, string | number | boolean>;
71
+ /** Idempotency key to prevent duplicate payment initiation */
72
+ idempotency_key?: string;
73
+ }
74
+
75
+ export interface ConversionQuote {
76
+ id: string;
77
+ business_id: string;
78
+ from_currency: string;
79
+ to_currency: string;
80
+ rate: number;
81
+ original_amount: number;
82
+ converted_amount: number;
83
+ is_used: boolean;
84
+ expires_at: string;
85
+ created_at: string;
86
+ }
87
+
88
+ // ── Response Types ─────────────────────────────────────────────────────────────
89
+
90
+ export interface DVADetails {
91
+ account_number: string;
92
+ bank_name: string;
93
+ account_name: string;
94
+ reference: string;
95
+ amount: number;
96
+ transaction_id: string;
97
+ expires_at: string;
98
+ }
99
+
100
+ export interface PaymentInitiateResponse {
101
+ id: string;
102
+ gateway_ref: string;
103
+ gateway: string;
104
+ status: string;
105
+ /** Normalised top-level checkout URL for gateway redirect */
106
+ checkout_url: string;
107
+ }
108
+
109
+ export interface TransactionVerifyResponse {
110
+ id: string;
111
+ status: string;
112
+ amount: number;
113
+ currency: string;
114
+ gateway_ref: string;
115
+ gateway?: string;
116
+ order_id?: string;
117
+ escrow_status?: string;
118
+ escrow_release_date?: string;
119
+ metadata_json?: Record<string, unknown>;
120
+ }