@inkress/admin-sdk 1.1.42 → 1.1.44

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.
package/dist/index.esm.js CHANGED
@@ -1913,7 +1913,7 @@ const ORDER_FIELD_TYPES = {
1913
1913
  status_on: 'number',
1914
1914
  uid: 'string',
1915
1915
  cart_id: 'number',
1916
- currency_id: 'number',
1916
+ currency_code: 'string',
1917
1917
  customer_id: 'number',
1918
1918
  payment_link_id: 'number',
1919
1919
  billing_plan_id: 'number',
@@ -1941,7 +1941,7 @@ const PRODUCT_FIELD_TYPES = {
1941
1941
  tag_ids: 'array',
1942
1942
  uid: 'string',
1943
1943
  category_id: 'number',
1944
- currency_id: 'number',
1944
+ currency_code: 'string',
1945
1945
  user_id: 'number',
1946
1946
  inserted_at: 'date',
1947
1947
  updated_at: 'date',
@@ -2033,7 +2033,7 @@ const BILLING_PLAN_FIELD_TYPES = {
2033
2033
  payout_value_limit: 'number',
2034
2034
  payout_percentage_limit: 'number',
2035
2035
  uid: 'string',
2036
- currency_id: 'number',
2036
+ currency_code: 'string',
2037
2037
  payment_provider_id: 'number',
2038
2038
  inserted_at: 'date',
2039
2039
  updated_at: 'date',
@@ -2074,7 +2074,7 @@ const PAYMENT_LINK_FIELD_TYPES = {
2074
2074
  status: 'number',
2075
2075
  kind: 'number',
2076
2076
  customer_id: 'number',
2077
- currency_id: 'number',
2077
+ currency_code: 'string',
2078
2078
  order_id: 'number',
2079
2079
  inserted_at: 'date',
2080
2080
  updated_at: 'date',
@@ -2118,7 +2118,7 @@ const FINANCIAL_REQUEST_FIELD_TYPES = {
2118
2118
  merchant_id: 'number',
2119
2119
  requester_id: 'number',
2120
2120
  reviewer_id: 'number',
2121
- currency_id: 'number',
2121
+ currency_code: 'string',
2122
2122
  evidence_file_id: 'number',
2123
2123
  inserted_at: 'date',
2124
2124
  updated_at: 'date',
@@ -2212,7 +2212,6 @@ const FEE_FIELD_TYPES = {
2212
2212
  currency_code: 'string',
2213
2213
  hash: 'string',
2214
2214
  fee_set_id: 'number',
2215
- currency_id: 'number',
2216
2215
  user_id: 'number',
2217
2216
  inserted_at: 'date',
2218
2217
  updated_at: 'date',
@@ -3470,6 +3469,62 @@ class PublicResource {
3470
3469
  }
3471
3470
  }
3472
3471
 
3472
+ /**
3473
+ * KYC document requirements by entity type
3474
+ * These are the standard documents required for each type of business entity
3475
+ */
3476
+ const KYC_DOCUMENT_REQUIREMENTS = {
3477
+ personal: [
3478
+ 'Proof of Identity',
3479
+ 'Proof of Address',
3480
+ 'Proof of Bank Account Ownership',
3481
+ ],
3482
+ 'sole-trader': [
3483
+ 'Proof of Identity',
3484
+ 'Proof of Address',
3485
+ 'Proof of Bank Account Ownership',
3486
+ 'Business Certificate',
3487
+ 'Articles of Incorporation',
3488
+ ],
3489
+ llc: [
3490
+ 'Proof of Identity',
3491
+ 'Proof of Address',
3492
+ 'Proof of Bank Account Ownership',
3493
+ 'Business Certificate',
3494
+ 'Articles of Incorporation',
3495
+ 'Annual Return',
3496
+ 'Notice of Directors',
3497
+ 'Notice of Secretary',
3498
+ 'Tax Compliance Certificate',
3499
+ ],
3500
+ 'non-profit': [
3501
+ 'Proof of Identity',
3502
+ 'Proof of Address',
3503
+ 'Proof of Bank Account Ownership',
3504
+ 'Business Certificate',
3505
+ 'Articles of Incorporation',
3506
+ 'Annual Return',
3507
+ ],
3508
+ alumni: [
3509
+ 'Proof of Identity',
3510
+ 'Proof of Address',
3511
+ 'Proof of Bank Account Ownership',
3512
+ 'Business Certificate',
3513
+ 'Articles of Incorporation',
3514
+ 'Annual Return',
3515
+ ],
3516
+ other: [
3517
+ 'Proof of Identity',
3518
+ 'Proof of Address',
3519
+ 'Proof of Bank Account Ownership',
3520
+ 'Business Certificate',
3521
+ 'Articles of Incorporation',
3522
+ 'Annual Return',
3523
+ 'Notice of Directors',
3524
+ 'Notice of Secretary',
3525
+ 'Tax Compliance Certificate',
3526
+ ],
3527
+ };
3473
3528
  // Field type definitions for query validation
3474
3529
  const KYC_FIELD_TYPES = {
3475
3530
  id: 'number',
@@ -3550,6 +3605,185 @@ class KycResource {
3550
3605
  async updateBankInfo(data) {
3551
3606
  return this.client.post('/legal_requests', data);
3552
3607
  }
3608
+ // ============================================================================
3609
+ // KYC DOCUMENT REQUIREMENTS & STATUS
3610
+ // ============================================================================
3611
+ /**
3612
+ * Get required KYC documents for a specific entity type
3613
+ * This is a client-side method that doesn't make an API call
3614
+ *
3615
+ * @param entityType - The type of business entity
3616
+ * @returns Array of required document types
3617
+ *
3618
+ * @example
3619
+ * const docs = kyc.getRequiredDocuments('llc');
3620
+ * // Returns: ['Proof of Identity', 'Proof of Address', ...]
3621
+ */
3622
+ getRequiredDocuments(entityType) {
3623
+ return [...KYC_DOCUMENT_REQUIREMENTS[entityType]];
3624
+ }
3625
+ /**
3626
+ * Get all KYC document requirements (without making an API call)
3627
+ * Useful for displaying the full list in your application
3628
+ *
3629
+ * @returns Complete mapping of entity types to required documents
3630
+ *
3631
+ * @example
3632
+ * const allRequirements = kyc.getAllRequirements();
3633
+ * console.log(allRequirements.llc); // ['Proof of Identity', ...]
3634
+ */
3635
+ getAllRequirements() {
3636
+ return { ...KYC_DOCUMENT_REQUIREMENTS };
3637
+ }
3638
+ /**
3639
+ * Get KYC requirements and submission status for the authenticated merchant
3640
+ * Fetches all KYC requests and maps them to required documents
3641
+ *
3642
+ * @param entityType - The merchant's business entity type
3643
+ * @returns Complete KYC requirements with submission status
3644
+ *
3645
+ * @example
3646
+ * const status = await kyc.getRequirementsStatus('llc');
3647
+ * console.log(`Completion: ${status.completion_percentage}%`);
3648
+ * console.log(`Approved: ${status.total_approved}/${status.total_required}`);
3649
+ *
3650
+ * // Check individual document status
3651
+ * status.document_statuses.forEach(doc => {
3652
+ * console.log(`${doc.document_type}: ${doc.status || 'not submitted'}`);
3653
+ * });
3654
+ */
3655
+ async getRequirementsStatus(entityType) {
3656
+ // Get required documents for this entity type
3657
+ const requiredDocuments = this.getRequiredDocuments(entityType);
3658
+ // Fetch all KYC requests for the authenticated merchant
3659
+ const params = {
3660
+ kind: 'document_submission',
3661
+ };
3662
+ const response = await this.list(params);
3663
+ if (response.state === 'error' || !response.result) {
3664
+ return {
3665
+ state: 'error',
3666
+ };
3667
+ }
3668
+ const kycRequests = response.result.entries || [];
3669
+ // Map submitted documents
3670
+ const submittedDocs = new Map();
3671
+ kycRequests.forEach(request => {
3672
+ var _a;
3673
+ const docType = (_a = request.data) === null || _a === void 0 ? void 0 : _a.document_type;
3674
+ if (docType && requiredDocuments.includes(docType)) {
3675
+ // Keep the most recent submission for each document type
3676
+ const existing = submittedDocs.get(docType);
3677
+ if (!existing || new Date(request.inserted_at) > new Date(existing.inserted_at)) {
3678
+ submittedDocs.set(docType, request);
3679
+ }
3680
+ }
3681
+ });
3682
+ // Build document statuses
3683
+ const documentStatuses = requiredDocuments.map(docType => {
3684
+ var _a;
3685
+ const submission = submittedDocs.get(docType);
3686
+ if (!submission) {
3687
+ return {
3688
+ document_type: docType,
3689
+ required: true,
3690
+ submitted: false,
3691
+ };
3692
+ }
3693
+ // Convert integer status to string using translator
3694
+ // The API returns status as a number, but the type says it's a string
3695
+ const statusString = StatusTranslator.toStringWithoutContext(submission.status, 'legal_request');
3696
+ // Map to our simplified status types
3697
+ let status;
3698
+ if (statusString) {
3699
+ if (statusString === 'pending' || statusString === 'in_review') {
3700
+ status = 'pending';
3701
+ }
3702
+ else if (statusString === 'approved') {
3703
+ status = 'approved';
3704
+ }
3705
+ else if (statusString === 'rejected') {
3706
+ status = 'rejected';
3707
+ }
3708
+ }
3709
+ const reviewedAt = submission.updated_at !== submission.inserted_at
3710
+ ? submission.updated_at
3711
+ : undefined;
3712
+ return {
3713
+ document_type: docType,
3714
+ required: true,
3715
+ submitted: true,
3716
+ status,
3717
+ submitted_at: submission.inserted_at,
3718
+ reviewed_at: reviewedAt,
3719
+ rejection_reason: (_a = submission.data) === null || _a === void 0 ? void 0 : _a.rejection_reason,
3720
+ };
3721
+ });
3722
+ // Calculate statistics
3723
+ const totalRequired = requiredDocuments.length;
3724
+ const totalSubmitted = documentStatuses.filter(d => d.submitted).length;
3725
+ const totalApproved = documentStatuses.filter(d => d.status === 'approved').length;
3726
+ const totalRejected = documentStatuses.filter(d => d.status === 'rejected').length;
3727
+ const totalPending = documentStatuses.filter(d => d.status === 'pending').length;
3728
+ const completionPercentage = totalRequired > 0
3729
+ ? Math.round((totalApproved / totalRequired) * 100)
3730
+ : 0;
3731
+ const isComplete = totalApproved === totalRequired;
3732
+ const requirements = {
3733
+ entity_type: entityType,
3734
+ required_documents: requiredDocuments,
3735
+ document_statuses: documentStatuses,
3736
+ total_required: totalRequired,
3737
+ total_submitted: totalSubmitted,
3738
+ total_approved: totalApproved,
3739
+ total_rejected: totalRejected,
3740
+ total_pending: totalPending,
3741
+ completion_percentage: completionPercentage,
3742
+ is_complete: isComplete,
3743
+ };
3744
+ return {
3745
+ state: 'ok',
3746
+ result: requirements,
3747
+ };
3748
+ }
3749
+ /**
3750
+ * Check if all required documents have been approved for the authenticated merchant
3751
+ *
3752
+ * @param entityType - The merchant's business entity type
3753
+ * @returns True if all required documents are approved
3754
+ *
3755
+ * @example
3756
+ * const isComplete = await kyc.isKycComplete('llc');
3757
+ * if (isComplete) {
3758
+ * console.log('Merchant is fully verified!');
3759
+ * }
3760
+ */
3761
+ async isKycComplete(entityType) {
3762
+ var _a;
3763
+ const response = await this.getRequirementsStatus(entityType);
3764
+ return ((_a = response.result) === null || _a === void 0 ? void 0 : _a.is_complete) || false;
3765
+ }
3766
+ /**
3767
+ * Get list of missing (not submitted or rejected) documents for the authenticated merchant
3768
+ *
3769
+ * @param entityType - The merchant's business entity type
3770
+ * @returns Array of document types that need to be submitted or resubmitted
3771
+ *
3772
+ * @example
3773
+ * const missing = await kyc.getMissingDocuments('llc');
3774
+ * if (missing.length > 0) {
3775
+ * console.log('Please submit:', missing.join(', '));
3776
+ * }
3777
+ */
3778
+ async getMissingDocuments(entityType) {
3779
+ const response = await this.getRequirementsStatus(entityType);
3780
+ if (response.state === 'error' || !response.result) {
3781
+ return [];
3782
+ }
3783
+ return response.result.document_statuses
3784
+ .filter(doc => !doc.submitted || doc.status === 'rejected')
3785
+ .map(doc => doc.document_type);
3786
+ }
3553
3787
  }
3554
3788
 
3555
3789
  class PaymentLinksResource {
@@ -3838,6 +4072,15 @@ class FinancialRequestsResource {
3838
4072
  }
3839
4073
  }
3840
4074
 
4075
+ let crypto;
4076
+ try {
4077
+ if (typeof require !== 'undefined') {
4078
+ crypto = require('crypto');
4079
+ }
4080
+ }
4081
+ catch (_a) {
4082
+ // Fallback for environments without Node.js crypto
4083
+ }
3841
4084
  class WebhookUrlsResource {
3842
4085
  constructor(client) {
3843
4086
  this.client = client;
@@ -3897,6 +4140,160 @@ class WebhookUrlsResource {
3897
4140
  createQueryBuilder() {
3898
4141
  return new WebhookUrlQueryBuilder(this);
3899
4142
  }
4143
+ // ============================================================================
4144
+ // WEBHOOK VERIFICATION METHODS
4145
+ // ============================================================================
4146
+ /**
4147
+ * Verify webhook signature using HMAC SHA256
4148
+ * Inkress webhooks use the format: crypto.mac(:hmac, :sha256, secret, body) |> Base.encode64()
4149
+ */
4150
+ verifySignature(body, signature, secret) {
4151
+ if (!crypto) {
4152
+ throw new Error('Node.js crypto module not available. Cannot verify webhook signature.');
4153
+ }
4154
+ try {
4155
+ // Generate expected signature using HMAC SHA256
4156
+ const expectedSignature = crypto
4157
+ .createHmac('sha256', secret)
4158
+ .update(body, 'utf8')
4159
+ .digest('base64');
4160
+ // Use constant-time comparison to prevent timing attacks
4161
+ return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expectedSignature));
4162
+ }
4163
+ catch (error) {
4164
+ return false;
4165
+ }
4166
+ }
4167
+ /**
4168
+ * Parse webhook payload from a string
4169
+ */
4170
+ parsePayload(payload) {
4171
+ try {
4172
+ const parsed = JSON.parse(payload);
4173
+ if (!parsed.id || !parsed.timestamp || !parsed.event) {
4174
+ throw new Error('Invalid webhook payload structure: missing required fields (id, timestamp, or event)');
4175
+ }
4176
+ return parsed;
4177
+ }
4178
+ catch (error) {
4179
+ if (error instanceof Error) {
4180
+ throw new Error(`Failed to parse webhook payload: ${error.message}`);
4181
+ }
4182
+ throw new Error('Failed to parse webhook payload');
4183
+ }
4184
+ }
4185
+ /**
4186
+ * Verify and parse an incoming webhook request
4187
+ * This method clones the request body, validates the signature, and returns the parsed payload
4188
+ *
4189
+ * @param request - The incoming HTTP request object with headers and body
4190
+ * @param secret - Your webhook secret for signature verification
4191
+ * @param options - Optional verification options (e.g., timestamp tolerance)
4192
+ * @returns Promise that resolves to the parsed webhook payload
4193
+ * @throws Error if signature verification fails or payload is invalid
4194
+ *
4195
+ * @example
4196
+ * ```typescript
4197
+ * // Express.js example
4198
+ * app.post('/webhooks', async (req, res) => {
4199
+ * try {
4200
+ * const payload = await sdk.webhookUrls.verifyRequest(
4201
+ * { headers: req.headers, body: req.body },
4202
+ * 'your-webhook-secret'
4203
+ * );
4204
+ *
4205
+ * // Process the webhook
4206
+ * console.log('Received webhook:', payload.event.type);
4207
+ *
4208
+ * res.status(200).json({ received: true });
4209
+ * } catch (error) {
4210
+ * console.error('Webhook verification failed:', error);
4211
+ * res.status(400).json({ error: error.message });
4212
+ * }
4213
+ * });
4214
+ * ```
4215
+ */
4216
+ async verifyRequest(request, secret, options) {
4217
+ // Extract signature from headers (case-insensitive)
4218
+ const signature = request.headers['x-inkress-webhook-signature'] ||
4219
+ request.headers['X-Inkress-Webhook-Signature'];
4220
+ if (!signature || typeof signature !== 'string') {
4221
+ throw new Error('Missing X-Inkress-Webhook-Signature header');
4222
+ }
4223
+ // Clone and ensure body is a string
4224
+ let body;
4225
+ if (typeof request.body === 'string') {
4226
+ body = request.body;
4227
+ }
4228
+ else if (request.body && typeof request.body === 'object') {
4229
+ body = JSON.stringify(request.body);
4230
+ }
4231
+ else {
4232
+ throw new Error('Invalid request body format: body must be a string or object');
4233
+ }
4234
+ // Verify signature
4235
+ const isValid = this.verifySignature(body, signature, secret);
4236
+ if (!isValid) {
4237
+ throw new Error('Webhook signature verification failed: signature does not match');
4238
+ }
4239
+ // Parse the payload
4240
+ const payload = this.parsePayload(body);
4241
+ // Optional: Verify timestamp tolerance
4242
+ if (options === null || options === void 0 ? void 0 : options.tolerance) {
4243
+ const currentTimestamp = Math.floor(Date.now() / 1000);
4244
+ const timeDifference = Math.abs(currentTimestamp - payload.timestamp);
4245
+ if (timeDifference > options.tolerance) {
4246
+ throw new Error(`Webhook timestamp outside tolerance window: ${timeDifference}s (max: ${options.tolerance}s)`);
4247
+ }
4248
+ }
4249
+ return payload;
4250
+ }
4251
+ /**
4252
+ * Verify webhook signature only (without parsing)
4253
+ * Useful for custom verification flows
4254
+ *
4255
+ * @param body - The raw webhook request body as a string
4256
+ * @param signature - The signature from X-Inkress-Webhook-Signature header
4257
+ * @param secret - Your webhook secret
4258
+ * @returns Promise that resolves to true if valid, rejects with error if invalid
4259
+ */
4260
+ async verify(body, signature, secret) {
4261
+ if (!this.verifySignature(body, signature, secret)) {
4262
+ throw new Error('Webhook signature verification failed');
4263
+ }
4264
+ return true;
4265
+ }
4266
+ /**
4267
+ * Generate webhook signature for testing
4268
+ * Matches Inkress signature generation: crypto.mac(:hmac, :sha256, secret, body) |> Base.encode64()
4269
+ *
4270
+ * @example
4271
+ * ```typescript
4272
+ * const testBody = JSON.stringify({ id: '123', timestamp: Date.now(), event: {...} });
4273
+ * const signature = sdk.webhookUrls.generateSignature(testBody, 'your-secret');
4274
+ * ```
4275
+ */
4276
+ generateSignature(body, secret) {
4277
+ if (!crypto) {
4278
+ throw new Error('Node.js crypto module not available. Cannot generate signature.');
4279
+ }
4280
+ return crypto
4281
+ .createHmac('sha256', secret)
4282
+ .update(body, 'utf8')
4283
+ .digest('base64');
4284
+ }
4285
+ /**
4286
+ * Extract event data from webhook payload with type safety
4287
+ *
4288
+ * @example
4289
+ * ```typescript
4290
+ * const payload = await sdk.webhookUrls.verifyRequest(request, secret);
4291
+ * const orderData = sdk.webhookUrls.extractEventData<Order>(payload);
4292
+ * ```
4293
+ */
4294
+ extractEventData(payload) {
4295
+ return payload.event.data;
4296
+ }
3900
4297
  }
3901
4298
 
3902
4299
  /**
@@ -4538,5 +4935,5 @@ class InkressSDK {
4538
4935
  }
4539
4936
  }
4540
4937
 
4541
- export { ADDRESS_FIELD_TYPES, AddressQueryBuilder, BILLING_PLAN_FIELD_TYPES, BillingPlanQueryBuilder, CATEGORY_FIELD_TYPES, CURRENCY_FIELD_TYPES, CategoryQueryBuilder, CurrencyQueryBuilder, EXCHANGE_RATE_FIELD_TYPES, ExchangeRateQueryBuilder, FEE_FIELD_TYPES, FINANCIAL_ACCOUNT_FIELD_TYPES, FINANCIAL_REQUEST_FIELD_TYPES, FeeQueryBuilder, FinancialAccountQueryBuilder, FinancialRequestQueryBuilder, HttpClient, InkressApiError, InkressSDK, MERCHANT_FIELD_TYPES, MerchantQueryBuilder, ORDER_FIELD_TYPES, OrderQueryBuilder, PAYMENT_LINK_FIELD_TYPES, PAYMENT_METHOD_FIELD_TYPES, PRODUCT_FIELD_TYPES, PaymentLinkQueryBuilder, PaymentMethodQueryBuilder, ProductQueryBuilder, QueryBuilder, SUBSCRIPTION_FIELD_TYPES, SubscriptionQueryBuilder, TOKEN_FIELD_TYPES, TRANSACTION_ENTRY_FIELD_TYPES, TokenQueryBuilder, TransactionEntryQueryBuilder, USER_FIELD_TYPES, UserQueryBuilder, WEBHOOK_URL_FIELD_TYPES, WebhookUrlQueryBuilder, InkressSDK as default, processQuery };
4938
+ export { ADDRESS_FIELD_TYPES, AddressQueryBuilder, BILLING_PLAN_FIELD_TYPES, BillingPlanQueryBuilder, CATEGORY_FIELD_TYPES, CURRENCY_FIELD_TYPES, CategoryQueryBuilder, CurrencyQueryBuilder, EXCHANGE_RATE_FIELD_TYPES, ExchangeRateQueryBuilder, FEE_FIELD_TYPES, FINANCIAL_ACCOUNT_FIELD_TYPES, FINANCIAL_REQUEST_FIELD_TYPES, FeeQueryBuilder, FinancialAccountQueryBuilder, FinancialRequestQueryBuilder, HttpClient, InkressApiError, InkressSDK, KYC_DOCUMENT_REQUIREMENTS, MERCHANT_FIELD_TYPES, MerchantQueryBuilder, ORDER_FIELD_TYPES, OrderQueryBuilder, PAYMENT_LINK_FIELD_TYPES, PAYMENT_METHOD_FIELD_TYPES, PRODUCT_FIELD_TYPES, PaymentLinkQueryBuilder, PaymentMethodQueryBuilder, ProductQueryBuilder, QueryBuilder, SUBSCRIPTION_FIELD_TYPES, SubscriptionQueryBuilder, TOKEN_FIELD_TYPES, TRANSACTION_ENTRY_FIELD_TYPES, TokenQueryBuilder, TransactionEntryQueryBuilder, USER_FIELD_TYPES, UserQueryBuilder, WEBHOOK_URL_FIELD_TYPES, WebhookUrlQueryBuilder, InkressSDK as default, processQuery };
4542
4939
  //# sourceMappingURL=index.esm.js.map