factuplan 0.7.0 → 0.10.0

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.d.mts CHANGED
@@ -122,6 +122,11 @@ interface CreateInvoiceInput {
122
122
  /** List of payment methods for multi-payment support. */
123
123
  payments?: InvoicePayment[];
124
124
  additionalInfo?: Record<string, string>;
125
+ /**
126
+ * Whether to send the authorized invoice by email to the customer.
127
+ * @default true
128
+ */
129
+ sendEmail?: boolean;
125
130
  }
126
131
  interface ImportByAccessKeyInput {
127
132
  /** 49-digit SRI access key (claveAcceso) of an already-authorized invoice */
@@ -217,11 +222,40 @@ interface WebhookReceiptData {
217
222
  customerName: string;
218
223
  customerIdentification: string;
219
224
  }
225
+ interface VoidInvoiceResponse {
226
+ id: string;
227
+ status: string;
228
+ accessKey: string | null;
229
+ voidReason: string;
230
+ message: string;
231
+ }
232
+ interface UpdateSequentialResponse {
233
+ branchCode: string;
234
+ emissionCode: string;
235
+ invoiceSequential: number;
236
+ updatedAt: string;
237
+ }
238
+ interface CertificateUploadResponse {
239
+ hasCertificate: boolean;
240
+ isExpired?: boolean;
241
+ daysUntilExpiry?: number | null;
242
+ ruc?: string;
243
+ legalName?: string;
244
+ expiresAt?: string;
245
+ /** True if a new contribuyente was automatically created from the certificate data */
246
+ created?: boolean;
247
+ }
220
248
  interface FactuplanOptions {
221
249
  /** Base URL of the API (default: https://api-rest.factuplan.com.ec/v1) */
222
250
  baseUrl?: string;
223
251
  /** Request timeout in milliseconds (default: 30000) */
224
252
  timeout?: number;
253
+ /**
254
+ * Default taxpayer RUC sent as `x-taxpayer-ruc` header in every request.
255
+ * Required for most operations (emit, sign, customers, products, etc.).
256
+ * Not required for `queryExternalByAccessKey`.
257
+ */
258
+ ruc?: string;
225
259
  }
226
260
  interface QueryExternalByAccessKeyInput {
227
261
  /** Clave de acceso de 49 dígitos del comprobante en el SRI */
@@ -248,6 +282,26 @@ interface QueryExternalByAccessKeyResponse {
248
282
  xmlBase64: string;
249
283
  }
250
284
 
285
+ type Requester$4 = (method: string, path: string, body?: unknown, params?: Record<string, string | number | undefined>) => Promise<unknown>;
286
+ declare class CertificatesResource {
287
+ private request;
288
+ constructor(request: Requester$4);
289
+ /**
290
+ * Get the certificate status for the current taxpayer (requires x-taxpayer-ruc header).
291
+ */
292
+ status(): Promise<CertificateStatus>;
293
+ /**
294
+ * Upload a P12 certificate.
295
+ * If the RUC in the certificate does not yet exist as a contribuyente in your
296
+ * workspace and your plan allows it, the contribuyente is created automatically
297
+ * and linked to your API key.
298
+ *
299
+ * @param file - P12 file as a Uint8Array/Buffer (Node.js) or Blob (browser)
300
+ * @param password - Password for the P12 file
301
+ */
302
+ upload(file: Uint8Array | Blob, password: string): Promise<CertificateUploadResponse>;
303
+ }
304
+
251
305
  type Requester$3 = (method: string, path: string, body?: unknown, params?: Record<string, string | number | undefined>) => Promise<unknown>;
252
306
  declare class CustomersResource {
253
307
  private request;
@@ -274,6 +328,8 @@ declare class InvoicesResource {
274
328
  downloadPdf(id: string): Promise<DownloadUrlResponse>;
275
329
  importByAccessKey(input: ImportByAccessKeyInput): Promise<Invoice>;
276
330
  queryExternalByAccessKey(input: QueryExternalByAccessKeyInput): Promise<QueryExternalByAccessKeyResponse>;
331
+ void(id: string, reason: string): Promise<VoidInvoiceResponse>;
332
+ updateSequential(branchCode: string, emissionCode: string, invoiceSequential: number): Promise<UpdateSequentialResponse>;
277
333
  }
278
334
 
279
335
  type Requester$1 = (method: string, path: string, body?: unknown, params?: Record<string, string | number | undefined>) => Promise<unknown>;
@@ -305,6 +361,8 @@ declare class Factuplan {
305
361
  private readonly apiKey;
306
362
  private readonly baseUrl;
307
363
  private readonly timeout;
364
+ private readonly options;
365
+ readonly certificates: CertificatesResource;
308
366
  readonly customers: CustomersResource;
309
367
  readonly products: ProductsResource;
310
368
  readonly invoices: InvoicesResource;
@@ -312,7 +370,6 @@ declare class Factuplan {
312
370
  static readonly webhooks: typeof WebhooksResource;
313
371
  constructor(apiKey: string, options?: FactuplanOptions);
314
372
  usage(): Promise<UsageResponse>;
315
- certificateStatus(): Promise<CertificateStatus>;
316
373
  private request;
317
374
  }
318
375
 
@@ -329,4 +386,4 @@ declare class RateLimitError extends FactuplanError {
329
386
  constructor(message?: string);
330
387
  }
331
388
 
332
- export { AuthenticationError, type CertificateStatus, type CreateCustomerInput, type CreateInvoiceInput, type CreateProductInput, type Customer, type CustomerListParams, type DownloadUrlResponse, Factuplan, FactuplanError, type FactuplanOptions, type ImportByAccessKeyInput, type Invoice, type InvoiceCustomer, type InvoiceItem, type InvoiceStatus, type PaginatedResponse, type Product, type ProductListParams, RateLimitError, type SignAndAuthorizeInput, type SignAndAuthorizeResponse, type SignOnlyInput, type SignOnlyResponse, type UpdateCustomerInput, type UpdateProductInput, type UsageResponse, type ValidateXmlInput, type ValidateXmlResponse, type VerifyResponse, type WebhookEvent, type WebhookReceiptData };
389
+ export { AuthenticationError, type CertificateStatus, type CertificateUploadResponse, CertificatesResource, type CreateCustomerInput, type CreateInvoiceInput, type CreateProductInput, type Customer, type CustomerListParams, type DownloadUrlResponse, Factuplan, FactuplanError, type FactuplanOptions, type ImportByAccessKeyInput, type Invoice, type InvoiceCustomer, type InvoiceItem, type InvoiceStatus, type PaginatedResponse, type Product, type ProductListParams, type QueryExternalByAccessKeyInput, type QueryExternalByAccessKeyResponse, RateLimitError, type SignAndAuthorizeInput, type SignAndAuthorizeResponse, type SignOnlyInput, type SignOnlyResponse, type UpdateCustomerInput, type UpdateProductInput, type UpdateSequentialResponse, type UsageResponse, type ValidateXmlInput, type ValidateXmlResponse, type VerifyResponse, type VoidInvoiceResponse, type WebhookEvent, type WebhookReceiptData };
package/dist/index.d.ts CHANGED
@@ -122,6 +122,11 @@ interface CreateInvoiceInput {
122
122
  /** List of payment methods for multi-payment support. */
123
123
  payments?: InvoicePayment[];
124
124
  additionalInfo?: Record<string, string>;
125
+ /**
126
+ * Whether to send the authorized invoice by email to the customer.
127
+ * @default true
128
+ */
129
+ sendEmail?: boolean;
125
130
  }
126
131
  interface ImportByAccessKeyInput {
127
132
  /** 49-digit SRI access key (claveAcceso) of an already-authorized invoice */
@@ -217,11 +222,40 @@ interface WebhookReceiptData {
217
222
  customerName: string;
218
223
  customerIdentification: string;
219
224
  }
225
+ interface VoidInvoiceResponse {
226
+ id: string;
227
+ status: string;
228
+ accessKey: string | null;
229
+ voidReason: string;
230
+ message: string;
231
+ }
232
+ interface UpdateSequentialResponse {
233
+ branchCode: string;
234
+ emissionCode: string;
235
+ invoiceSequential: number;
236
+ updatedAt: string;
237
+ }
238
+ interface CertificateUploadResponse {
239
+ hasCertificate: boolean;
240
+ isExpired?: boolean;
241
+ daysUntilExpiry?: number | null;
242
+ ruc?: string;
243
+ legalName?: string;
244
+ expiresAt?: string;
245
+ /** True if a new contribuyente was automatically created from the certificate data */
246
+ created?: boolean;
247
+ }
220
248
  interface FactuplanOptions {
221
249
  /** Base URL of the API (default: https://api-rest.factuplan.com.ec/v1) */
222
250
  baseUrl?: string;
223
251
  /** Request timeout in milliseconds (default: 30000) */
224
252
  timeout?: number;
253
+ /**
254
+ * Default taxpayer RUC sent as `x-taxpayer-ruc` header in every request.
255
+ * Required for most operations (emit, sign, customers, products, etc.).
256
+ * Not required for `queryExternalByAccessKey`.
257
+ */
258
+ ruc?: string;
225
259
  }
226
260
  interface QueryExternalByAccessKeyInput {
227
261
  /** Clave de acceso de 49 dígitos del comprobante en el SRI */
@@ -248,6 +282,26 @@ interface QueryExternalByAccessKeyResponse {
248
282
  xmlBase64: string;
249
283
  }
250
284
 
285
+ type Requester$4 = (method: string, path: string, body?: unknown, params?: Record<string, string | number | undefined>) => Promise<unknown>;
286
+ declare class CertificatesResource {
287
+ private request;
288
+ constructor(request: Requester$4);
289
+ /**
290
+ * Get the certificate status for the current taxpayer (requires x-taxpayer-ruc header).
291
+ */
292
+ status(): Promise<CertificateStatus>;
293
+ /**
294
+ * Upload a P12 certificate.
295
+ * If the RUC in the certificate does not yet exist as a contribuyente in your
296
+ * workspace and your plan allows it, the contribuyente is created automatically
297
+ * and linked to your API key.
298
+ *
299
+ * @param file - P12 file as a Uint8Array/Buffer (Node.js) or Blob (browser)
300
+ * @param password - Password for the P12 file
301
+ */
302
+ upload(file: Uint8Array | Blob, password: string): Promise<CertificateUploadResponse>;
303
+ }
304
+
251
305
  type Requester$3 = (method: string, path: string, body?: unknown, params?: Record<string, string | number | undefined>) => Promise<unknown>;
252
306
  declare class CustomersResource {
253
307
  private request;
@@ -274,6 +328,8 @@ declare class InvoicesResource {
274
328
  downloadPdf(id: string): Promise<DownloadUrlResponse>;
275
329
  importByAccessKey(input: ImportByAccessKeyInput): Promise<Invoice>;
276
330
  queryExternalByAccessKey(input: QueryExternalByAccessKeyInput): Promise<QueryExternalByAccessKeyResponse>;
331
+ void(id: string, reason: string): Promise<VoidInvoiceResponse>;
332
+ updateSequential(branchCode: string, emissionCode: string, invoiceSequential: number): Promise<UpdateSequentialResponse>;
277
333
  }
278
334
 
279
335
  type Requester$1 = (method: string, path: string, body?: unknown, params?: Record<string, string | number | undefined>) => Promise<unknown>;
@@ -305,6 +361,8 @@ declare class Factuplan {
305
361
  private readonly apiKey;
306
362
  private readonly baseUrl;
307
363
  private readonly timeout;
364
+ private readonly options;
365
+ readonly certificates: CertificatesResource;
308
366
  readonly customers: CustomersResource;
309
367
  readonly products: ProductsResource;
310
368
  readonly invoices: InvoicesResource;
@@ -312,7 +370,6 @@ declare class Factuplan {
312
370
  static readonly webhooks: typeof WebhooksResource;
313
371
  constructor(apiKey: string, options?: FactuplanOptions);
314
372
  usage(): Promise<UsageResponse>;
315
- certificateStatus(): Promise<CertificateStatus>;
316
373
  private request;
317
374
  }
318
375
 
@@ -329,4 +386,4 @@ declare class RateLimitError extends FactuplanError {
329
386
  constructor(message?: string);
330
387
  }
331
388
 
332
- export { AuthenticationError, type CertificateStatus, type CreateCustomerInput, type CreateInvoiceInput, type CreateProductInput, type Customer, type CustomerListParams, type DownloadUrlResponse, Factuplan, FactuplanError, type FactuplanOptions, type ImportByAccessKeyInput, type Invoice, type InvoiceCustomer, type InvoiceItem, type InvoiceStatus, type PaginatedResponse, type Product, type ProductListParams, RateLimitError, type SignAndAuthorizeInput, type SignAndAuthorizeResponse, type SignOnlyInput, type SignOnlyResponse, type UpdateCustomerInput, type UpdateProductInput, type UsageResponse, type ValidateXmlInput, type ValidateXmlResponse, type VerifyResponse, type WebhookEvent, type WebhookReceiptData };
389
+ export { AuthenticationError, type CertificateStatus, type CertificateUploadResponse, CertificatesResource, type CreateCustomerInput, type CreateInvoiceInput, type CreateProductInput, type Customer, type CustomerListParams, type DownloadUrlResponse, Factuplan, FactuplanError, type FactuplanOptions, type ImportByAccessKeyInput, type Invoice, type InvoiceCustomer, type InvoiceItem, type InvoiceStatus, type PaginatedResponse, type Product, type ProductListParams, type QueryExternalByAccessKeyInput, type QueryExternalByAccessKeyResponse, RateLimitError, type SignAndAuthorizeInput, type SignAndAuthorizeResponse, type SignOnlyInput, type SignOnlyResponse, type UpdateCustomerInput, type UpdateProductInput, type UpdateSequentialResponse, type UsageResponse, type ValidateXmlInput, type ValidateXmlResponse, type VerifyResponse, type VoidInvoiceResponse, type WebhookEvent, type WebhookReceiptData };
package/dist/index.js CHANGED
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
23
  AuthenticationError: () => AuthenticationError,
24
+ CertificatesResource: () => CertificatesResource,
24
25
  Factuplan: () => Factuplan,
25
26
  FactuplanError: () => FactuplanError,
26
27
  RateLimitError: () => RateLimitError
@@ -50,6 +51,35 @@ var RateLimitError = class extends FactuplanError {
50
51
  }
51
52
  };
52
53
 
54
+ // src/resources/certificates.ts
55
+ var CertificatesResource = class {
56
+ constructor(request) {
57
+ this.request = request;
58
+ }
59
+ /**
60
+ * Get the certificate status for the current taxpayer (requires x-taxpayer-ruc header).
61
+ */
62
+ async status() {
63
+ return this.request("GET", "/developer/certificate/status");
64
+ }
65
+ /**
66
+ * Upload a P12 certificate.
67
+ * If the RUC in the certificate does not yet exist as a contribuyente in your
68
+ * workspace and your plan allows it, the contribuyente is created automatically
69
+ * and linked to your API key.
70
+ *
71
+ * @param file - P12 file as a Uint8Array/Buffer (Node.js) or Blob (browser)
72
+ * @param password - Password for the P12 file
73
+ */
74
+ async upload(file, password) {
75
+ return this.request(
76
+ "POST",
77
+ "/developer/certificate",
78
+ { __formData: true, file, password }
79
+ );
80
+ }
81
+ };
82
+
53
83
  // src/resources/customers.ts
54
84
  var CustomersResource = class {
55
85
  constructor(request) {
@@ -114,6 +144,20 @@ var InvoicesResource = class {
114
144
  input
115
145
  );
116
146
  }
147
+ async void(id, reason) {
148
+ return this.request(
149
+ "POST",
150
+ `/developer/receipts/${id}/void`,
151
+ { reason }
152
+ );
153
+ }
154
+ async updateSequential(branchCode, emissionCode, invoiceSequential) {
155
+ return this.request(
156
+ "PATCH",
157
+ "/developer/invoices/sequential",
158
+ { branchCode, emissionCode, invoiceSequential }
159
+ );
160
+ }
117
161
  };
118
162
 
119
163
  // src/resources/products.ts
@@ -167,9 +211,11 @@ var Factuplan = class {
167
211
  constructor(apiKey, options) {
168
212
  if (!apiKey) throw new Error("API key is required");
169
213
  this.apiKey = apiKey;
214
+ this.options = options;
170
215
  this.baseUrl = (options?.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
171
216
  this.timeout = options?.timeout ?? DEFAULT_TIMEOUT;
172
217
  const requester = this.request.bind(this);
218
+ this.certificates = new CertificatesResource(requester);
173
219
  this.customers = new CustomersResource(requester);
174
220
  this.products = new ProductsResource(requester);
175
221
  this.invoices = new InvoicesResource(requester);
@@ -178,9 +224,6 @@ var Factuplan = class {
178
224
  async usage() {
179
225
  return this.request("GET", "/developer/usage");
180
226
  }
181
- async certificateStatus() {
182
- return this.request("GET", "/developer/certificate/status");
183
- }
184
227
  async request(method, path, body, params) {
185
228
  let url = `${this.baseUrl}${path}`;
186
229
  if (params) {
@@ -197,13 +240,27 @@ var Factuplan = class {
197
240
  "x-api-key": this.apiKey,
198
241
  Accept: "application/json"
199
242
  };
243
+ if (this.options?.ruc) {
244
+ headers["x-taxpayer-ruc"] = this.options.ruc;
245
+ }
246
+ let fetchBody;
200
247
  if (body !== void 0) {
201
- headers["Content-Type"] = "application/json";
248
+ if (body !== null && typeof body === "object" && body.__formData === true) {
249
+ const { file, password } = body;
250
+ const fd = new FormData();
251
+ const blob = file instanceof Blob ? file : new Blob([file]);
252
+ fd.append("file", blob, "certificate.p12");
253
+ fd.append("password", password);
254
+ fetchBody = fd;
255
+ } else {
256
+ headers["Content-Type"] = "application/json";
257
+ fetchBody = JSON.stringify(body);
258
+ }
202
259
  }
203
260
  const response = await fetch(url, {
204
261
  method,
205
262
  headers,
206
- body: body !== void 0 ? JSON.stringify(body) : void 0,
263
+ body: fetchBody,
207
264
  signal: AbortSignal.timeout(this.timeout)
208
265
  });
209
266
  if (response.status === 204) return void 0;
@@ -231,6 +288,7 @@ Factuplan.webhooks = WebhooksResource;
231
288
  // Annotate the CommonJS export names for ESM import in node:
232
289
  0 && (module.exports = {
233
290
  AuthenticationError,
291
+ CertificatesResource,
234
292
  Factuplan,
235
293
  FactuplanError,
236
294
  RateLimitError
package/dist/index.mjs CHANGED
@@ -21,6 +21,35 @@ var RateLimitError = class extends FactuplanError {
21
21
  }
22
22
  };
23
23
 
24
+ // src/resources/certificates.ts
25
+ var CertificatesResource = class {
26
+ constructor(request) {
27
+ this.request = request;
28
+ }
29
+ /**
30
+ * Get the certificate status for the current taxpayer (requires x-taxpayer-ruc header).
31
+ */
32
+ async status() {
33
+ return this.request("GET", "/developer/certificate/status");
34
+ }
35
+ /**
36
+ * Upload a P12 certificate.
37
+ * If the RUC in the certificate does not yet exist as a contribuyente in your
38
+ * workspace and your plan allows it, the contribuyente is created automatically
39
+ * and linked to your API key.
40
+ *
41
+ * @param file - P12 file as a Uint8Array/Buffer (Node.js) or Blob (browser)
42
+ * @param password - Password for the P12 file
43
+ */
44
+ async upload(file, password) {
45
+ return this.request(
46
+ "POST",
47
+ "/developer/certificate",
48
+ { __formData: true, file, password }
49
+ );
50
+ }
51
+ };
52
+
24
53
  // src/resources/customers.ts
25
54
  var CustomersResource = class {
26
55
  constructor(request) {
@@ -85,6 +114,20 @@ var InvoicesResource = class {
85
114
  input
86
115
  );
87
116
  }
117
+ async void(id, reason) {
118
+ return this.request(
119
+ "POST",
120
+ `/developer/receipts/${id}/void`,
121
+ { reason }
122
+ );
123
+ }
124
+ async updateSequential(branchCode, emissionCode, invoiceSequential) {
125
+ return this.request(
126
+ "PATCH",
127
+ "/developer/invoices/sequential",
128
+ { branchCode, emissionCode, invoiceSequential }
129
+ );
130
+ }
88
131
  };
89
132
 
90
133
  // src/resources/products.ts
@@ -138,9 +181,11 @@ var Factuplan = class {
138
181
  constructor(apiKey, options) {
139
182
  if (!apiKey) throw new Error("API key is required");
140
183
  this.apiKey = apiKey;
184
+ this.options = options;
141
185
  this.baseUrl = (options?.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
142
186
  this.timeout = options?.timeout ?? DEFAULT_TIMEOUT;
143
187
  const requester = this.request.bind(this);
188
+ this.certificates = new CertificatesResource(requester);
144
189
  this.customers = new CustomersResource(requester);
145
190
  this.products = new ProductsResource(requester);
146
191
  this.invoices = new InvoicesResource(requester);
@@ -149,9 +194,6 @@ var Factuplan = class {
149
194
  async usage() {
150
195
  return this.request("GET", "/developer/usage");
151
196
  }
152
- async certificateStatus() {
153
- return this.request("GET", "/developer/certificate/status");
154
- }
155
197
  async request(method, path, body, params) {
156
198
  let url = `${this.baseUrl}${path}`;
157
199
  if (params) {
@@ -168,13 +210,27 @@ var Factuplan = class {
168
210
  "x-api-key": this.apiKey,
169
211
  Accept: "application/json"
170
212
  };
213
+ if (this.options?.ruc) {
214
+ headers["x-taxpayer-ruc"] = this.options.ruc;
215
+ }
216
+ let fetchBody;
171
217
  if (body !== void 0) {
172
- headers["Content-Type"] = "application/json";
218
+ if (body !== null && typeof body === "object" && body.__formData === true) {
219
+ const { file, password } = body;
220
+ const fd = new FormData();
221
+ const blob = file instanceof Blob ? file : new Blob([file]);
222
+ fd.append("file", blob, "certificate.p12");
223
+ fd.append("password", password);
224
+ fetchBody = fd;
225
+ } else {
226
+ headers["Content-Type"] = "application/json";
227
+ fetchBody = JSON.stringify(body);
228
+ }
173
229
  }
174
230
  const response = await fetch(url, {
175
231
  method,
176
232
  headers,
177
- body: body !== void 0 ? JSON.stringify(body) : void 0,
233
+ body: fetchBody,
178
234
  signal: AbortSignal.timeout(this.timeout)
179
235
  });
180
236
  if (response.status === 204) return void 0;
@@ -201,6 +257,7 @@ var Factuplan = class {
201
257
  Factuplan.webhooks = WebhooksResource;
202
258
  export {
203
259
  AuthenticationError,
260
+ CertificatesResource,
204
261
  Factuplan,
205
262
  FactuplanError,
206
263
  RateLimitError
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "factuplan",
3
- "version": "0.7.0",
3
+ "version": "0.10.0",
4
4
  "description": "Official Factuplan SDK for JavaScript & TypeScript — Create electronic invoices for Ecuador (SRI)",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",