factuplan 0.2.1 → 0.4.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.
package/README.md CHANGED
@@ -129,6 +129,58 @@ const { url } = await factuplan.invoices.downloadXml('invoice-id');
129
129
  const { url } = await factuplan.invoices.downloadPdf('invoice-id');
130
130
  ```
131
131
 
132
+ ### Firmar y autorizar XML (Modo B)
133
+
134
+ Si ya tienes tu XML generado (sin firmar), puedes enviarlo para que Factuplan lo firme con tu certificado y lo autorice ante el SRI:
135
+
136
+ ```typescript
137
+ import { readFileSync } from 'fs';
138
+
139
+ // Leer XML sin firmar
140
+ const xml = readFileSync('./factura.xml', 'utf-8');
141
+
142
+ // Firmar y autorizar
143
+ const result = await factuplan.invoices.signAndAuthorize({ xml });
144
+
145
+ console.log(result.accessKey); // Clave de acceso SRI
146
+ console.log(result.status); // Estado del comprobante
147
+
148
+ // Consultar estado de autorizacion
149
+ const status = await factuplan.invoices.getStatus(result.id);
150
+
151
+ // Descargar XML autorizado
152
+ const { url } = await factuplan.invoices.downloadXml(result.id);
153
+ ```
154
+
155
+ ### Solo firmar XML (Modo C)
156
+
157
+ Firma el XML con tu certificado sin enviarlo al SRI:
158
+
159
+ ```typescript
160
+ const { signedXml } = await factuplan.invoices.signOnly({ xml });
161
+ ```
162
+
163
+ ### Validar XML
164
+
165
+ Valida la estructura de un XML sin procesarlo:
166
+
167
+ ```typescript
168
+ const { valid, errors } = await factuplan.invoices.validateXml({ xml });
169
+ if (!valid) {
170
+ console.log('Errores:', errors);
171
+ }
172
+ ```
173
+
174
+ ### Verificar autorizacion
175
+
176
+ Consulta el estado de autorizacion de un comprobante por su clave de acceso:
177
+
178
+ ```typescript
179
+ const result = await factuplan.invoices.verify('0104202601099337815000110010010000000011234567890');
180
+ console.log(result.authorized); // true/false
181
+ console.log(result.authorizationNumber); // Numero de autorizacion
182
+ ```
183
+
132
184
  ### Uso y certificado
133
185
 
134
186
  ```typescript
package/dist/index.d.mts CHANGED
@@ -133,6 +133,39 @@ interface DownloadUrlResponse {
133
133
  url: string;
134
134
  s3Key?: string;
135
135
  }
136
+ interface SignAndAuthorizeInput {
137
+ /** Unsigned XML string */
138
+ xml: string;
139
+ }
140
+ interface SignAndAuthorizeResponse {
141
+ id: string;
142
+ accessKey: string;
143
+ status: string;
144
+ }
145
+ interface SignOnlyInput {
146
+ /** Unsigned XML string */
147
+ xml: string;
148
+ }
149
+ interface SignOnlyResponse {
150
+ signedXml: string;
151
+ }
152
+ interface ValidateXmlInput {
153
+ /** XML string to validate */
154
+ xml: string;
155
+ }
156
+ interface ValidateXmlResponse {
157
+ valid: boolean;
158
+ errors: string[];
159
+ }
160
+ interface VerifyResponse {
161
+ authorized: boolean;
162
+ authorizationNumber?: string;
163
+ authorizationDate?: string;
164
+ messages?: Array<{
165
+ code?: string;
166
+ message?: string;
167
+ }>;
168
+ }
136
169
  interface UsageResponse {
137
170
  apiKeyId: string;
138
171
  month: string;
@@ -149,6 +182,24 @@ interface CertificateStatus {
149
182
  legalName?: string;
150
183
  expiresAt?: string;
151
184
  }
185
+ interface WebhookEvent {
186
+ id: string;
187
+ event: string;
188
+ timestamp: string;
189
+ data: WebhookReceiptData;
190
+ webhookId: string;
191
+ attempt: number;
192
+ }
193
+ interface WebhookReceiptData {
194
+ receiptId: string;
195
+ type: string;
196
+ accessKey: string;
197
+ authorizationNumber: string;
198
+ documentNumber: string;
199
+ total: string;
200
+ customerName: string;
201
+ customerIdentification: string;
202
+ }
152
203
  interface FactuplanOptions {
153
204
  /** Base URL of the API (default: https://api.factuplan.com/api/v1) */
154
205
  baseUrl?: string;
@@ -156,10 +207,10 @@ interface FactuplanOptions {
156
207
  timeout?: number;
157
208
  }
158
209
 
159
- type Requester$2 = (method: string, path: string, body?: unknown, params?: Record<string, string | number | undefined>) => Promise<unknown>;
210
+ type Requester$3 = (method: string, path: string, body?: unknown, params?: Record<string, string | number | undefined>) => Promise<unknown>;
160
211
  declare class CustomersResource {
161
212
  private request;
162
- constructor(request: Requester$2);
213
+ constructor(request: Requester$3);
163
214
  create(input: CreateCustomerInput): Promise<Customer>;
164
215
  list(params?: CustomerListParams): Promise<PaginatedResponse<Customer>>;
165
216
  get(id: string): Promise<Customer>;
@@ -167,21 +218,25 @@ declare class CustomersResource {
167
218
  delete(id: string): Promise<void>;
168
219
  }
169
220
 
170
- type Requester$1 = (method: string, path: string, body?: unknown) => Promise<unknown>;
221
+ type Requester$2 = (method: string, path: string, body?: unknown) => Promise<unknown>;
171
222
  declare class InvoicesResource {
172
223
  private request;
173
- constructor(request: Requester$1);
224
+ constructor(request: Requester$2);
174
225
  create(input: CreateInvoiceInput): Promise<Invoice>;
226
+ signAndAuthorize(input: SignAndAuthorizeInput): Promise<SignAndAuthorizeResponse>;
227
+ signOnly(input: SignOnlyInput): Promise<SignOnlyResponse>;
228
+ validateXml(input: ValidateXmlInput): Promise<ValidateXmlResponse>;
229
+ verify(accessKey: string): Promise<VerifyResponse>;
175
230
  get(id: string): Promise<Record<string, unknown>>;
176
231
  getStatus(id: string): Promise<InvoiceStatus>;
177
232
  downloadXml(id: string): Promise<DownloadUrlResponse>;
178
233
  downloadPdf(id: string): Promise<DownloadUrlResponse>;
179
234
  }
180
235
 
181
- type Requester = (method: string, path: string, body?: unknown, params?: Record<string, string | number | undefined>) => Promise<unknown>;
236
+ type Requester$1 = (method: string, path: string, body?: unknown, params?: Record<string, string | number | undefined>) => Promise<unknown>;
182
237
  declare class ProductsResource {
183
238
  private request;
184
- constructor(request: Requester);
239
+ constructor(request: Requester$1);
185
240
  create(input: CreateProductInput): Promise<Product>;
186
241
  list(params?: ProductListParams): Promise<PaginatedResponse<Product>>;
187
242
  get(id: string): Promise<Product>;
@@ -189,6 +244,20 @@ declare class ProductsResource {
189
244
  delete(id: string): Promise<void>;
190
245
  }
191
246
 
247
+ type Requester = (method: string, path: string, body?: unknown, params?: Record<string, string | number | undefined>) => Promise<unknown>;
248
+ declare class WebhooksResource {
249
+ private readonly request;
250
+ constructor(requester: Requester);
251
+ /**
252
+ * Verify that a receipt (document) exists in the API.
253
+ * This is a second layer of verification beyond signature checking.
254
+ *
255
+ * @param receiptId - The receipt ID from the webhook payload
256
+ * @returns The receipt object if it exists, or `null` if not found
257
+ */
258
+ verifyReceipt(receiptId: string): Promise<Record<string, unknown> | null>;
259
+ }
260
+
192
261
  declare class Factuplan {
193
262
  private readonly apiKey;
194
263
  private readonly baseUrl;
@@ -196,6 +265,8 @@ declare class Factuplan {
196
265
  readonly customers: CustomersResource;
197
266
  readonly products: ProductsResource;
198
267
  readonly invoices: InvoicesResource;
268
+ readonly webhooks: WebhooksResource;
269
+ static readonly webhooks: typeof WebhooksResource;
199
270
  constructor(apiKey: string, options?: FactuplanOptions);
200
271
  usage(): Promise<UsageResponse>;
201
272
  certificateStatus(): Promise<CertificateStatus>;
@@ -215,4 +286,4 @@ declare class RateLimitError extends FactuplanError {
215
286
  constructor(message?: string);
216
287
  }
217
288
 
218
- export { AuthenticationError, type CertificateStatus, type CreateCustomerInput, type CreateInvoiceInput, type CreateProductInput, type Customer, type CustomerListParams, type DownloadUrlResponse, Factuplan, FactuplanError, type FactuplanOptions, type Invoice, type InvoiceCustomer, type InvoiceItem, type InvoiceStatus, type PaginatedResponse, type Product, type ProductListParams, RateLimitError, type UpdateCustomerInput, type UpdateProductInput, type UsageResponse };
289
+ export { AuthenticationError, type CertificateStatus, type CreateCustomerInput, type CreateInvoiceInput, type CreateProductInput, type Customer, type CustomerListParams, type DownloadUrlResponse, Factuplan, FactuplanError, type FactuplanOptions, 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 };
package/dist/index.d.ts CHANGED
@@ -133,6 +133,39 @@ interface DownloadUrlResponse {
133
133
  url: string;
134
134
  s3Key?: string;
135
135
  }
136
+ interface SignAndAuthorizeInput {
137
+ /** Unsigned XML string */
138
+ xml: string;
139
+ }
140
+ interface SignAndAuthorizeResponse {
141
+ id: string;
142
+ accessKey: string;
143
+ status: string;
144
+ }
145
+ interface SignOnlyInput {
146
+ /** Unsigned XML string */
147
+ xml: string;
148
+ }
149
+ interface SignOnlyResponse {
150
+ signedXml: string;
151
+ }
152
+ interface ValidateXmlInput {
153
+ /** XML string to validate */
154
+ xml: string;
155
+ }
156
+ interface ValidateXmlResponse {
157
+ valid: boolean;
158
+ errors: string[];
159
+ }
160
+ interface VerifyResponse {
161
+ authorized: boolean;
162
+ authorizationNumber?: string;
163
+ authorizationDate?: string;
164
+ messages?: Array<{
165
+ code?: string;
166
+ message?: string;
167
+ }>;
168
+ }
136
169
  interface UsageResponse {
137
170
  apiKeyId: string;
138
171
  month: string;
@@ -149,6 +182,24 @@ interface CertificateStatus {
149
182
  legalName?: string;
150
183
  expiresAt?: string;
151
184
  }
185
+ interface WebhookEvent {
186
+ id: string;
187
+ event: string;
188
+ timestamp: string;
189
+ data: WebhookReceiptData;
190
+ webhookId: string;
191
+ attempt: number;
192
+ }
193
+ interface WebhookReceiptData {
194
+ receiptId: string;
195
+ type: string;
196
+ accessKey: string;
197
+ authorizationNumber: string;
198
+ documentNumber: string;
199
+ total: string;
200
+ customerName: string;
201
+ customerIdentification: string;
202
+ }
152
203
  interface FactuplanOptions {
153
204
  /** Base URL of the API (default: https://api.factuplan.com/api/v1) */
154
205
  baseUrl?: string;
@@ -156,10 +207,10 @@ interface FactuplanOptions {
156
207
  timeout?: number;
157
208
  }
158
209
 
159
- type Requester$2 = (method: string, path: string, body?: unknown, params?: Record<string, string | number | undefined>) => Promise<unknown>;
210
+ type Requester$3 = (method: string, path: string, body?: unknown, params?: Record<string, string | number | undefined>) => Promise<unknown>;
160
211
  declare class CustomersResource {
161
212
  private request;
162
- constructor(request: Requester$2);
213
+ constructor(request: Requester$3);
163
214
  create(input: CreateCustomerInput): Promise<Customer>;
164
215
  list(params?: CustomerListParams): Promise<PaginatedResponse<Customer>>;
165
216
  get(id: string): Promise<Customer>;
@@ -167,21 +218,25 @@ declare class CustomersResource {
167
218
  delete(id: string): Promise<void>;
168
219
  }
169
220
 
170
- type Requester$1 = (method: string, path: string, body?: unknown) => Promise<unknown>;
221
+ type Requester$2 = (method: string, path: string, body?: unknown) => Promise<unknown>;
171
222
  declare class InvoicesResource {
172
223
  private request;
173
- constructor(request: Requester$1);
224
+ constructor(request: Requester$2);
174
225
  create(input: CreateInvoiceInput): Promise<Invoice>;
226
+ signAndAuthorize(input: SignAndAuthorizeInput): Promise<SignAndAuthorizeResponse>;
227
+ signOnly(input: SignOnlyInput): Promise<SignOnlyResponse>;
228
+ validateXml(input: ValidateXmlInput): Promise<ValidateXmlResponse>;
229
+ verify(accessKey: string): Promise<VerifyResponse>;
175
230
  get(id: string): Promise<Record<string, unknown>>;
176
231
  getStatus(id: string): Promise<InvoiceStatus>;
177
232
  downloadXml(id: string): Promise<DownloadUrlResponse>;
178
233
  downloadPdf(id: string): Promise<DownloadUrlResponse>;
179
234
  }
180
235
 
181
- type Requester = (method: string, path: string, body?: unknown, params?: Record<string, string | number | undefined>) => Promise<unknown>;
236
+ type Requester$1 = (method: string, path: string, body?: unknown, params?: Record<string, string | number | undefined>) => Promise<unknown>;
182
237
  declare class ProductsResource {
183
238
  private request;
184
- constructor(request: Requester);
239
+ constructor(request: Requester$1);
185
240
  create(input: CreateProductInput): Promise<Product>;
186
241
  list(params?: ProductListParams): Promise<PaginatedResponse<Product>>;
187
242
  get(id: string): Promise<Product>;
@@ -189,6 +244,20 @@ declare class ProductsResource {
189
244
  delete(id: string): Promise<void>;
190
245
  }
191
246
 
247
+ type Requester = (method: string, path: string, body?: unknown, params?: Record<string, string | number | undefined>) => Promise<unknown>;
248
+ declare class WebhooksResource {
249
+ private readonly request;
250
+ constructor(requester: Requester);
251
+ /**
252
+ * Verify that a receipt (document) exists in the API.
253
+ * This is a second layer of verification beyond signature checking.
254
+ *
255
+ * @param receiptId - The receipt ID from the webhook payload
256
+ * @returns The receipt object if it exists, or `null` if not found
257
+ */
258
+ verifyReceipt(receiptId: string): Promise<Record<string, unknown> | null>;
259
+ }
260
+
192
261
  declare class Factuplan {
193
262
  private readonly apiKey;
194
263
  private readonly baseUrl;
@@ -196,6 +265,8 @@ declare class Factuplan {
196
265
  readonly customers: CustomersResource;
197
266
  readonly products: ProductsResource;
198
267
  readonly invoices: InvoicesResource;
268
+ readonly webhooks: WebhooksResource;
269
+ static readonly webhooks: typeof WebhooksResource;
199
270
  constructor(apiKey: string, options?: FactuplanOptions);
200
271
  usage(): Promise<UsageResponse>;
201
272
  certificateStatus(): Promise<CertificateStatus>;
@@ -215,4 +286,4 @@ declare class RateLimitError extends FactuplanError {
215
286
  constructor(message?: string);
216
287
  }
217
288
 
218
- export { AuthenticationError, type CertificateStatus, type CreateCustomerInput, type CreateInvoiceInput, type CreateProductInput, type Customer, type CustomerListParams, type DownloadUrlResponse, Factuplan, FactuplanError, type FactuplanOptions, type Invoice, type InvoiceCustomer, type InvoiceItem, type InvoiceStatus, type PaginatedResponse, type Product, type ProductListParams, RateLimitError, type UpdateCustomerInput, type UpdateProductInput, type UsageResponse };
289
+ export { AuthenticationError, type CertificateStatus, type CreateCustomerInput, type CreateInvoiceInput, type CreateProductInput, type Customer, type CustomerListParams, type DownloadUrlResponse, Factuplan, FactuplanError, type FactuplanOptions, 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 };
package/dist/index.js CHANGED
@@ -80,6 +80,18 @@ var InvoicesResource = class {
80
80
  async create(input) {
81
81
  return this.request("POST", "/developer/invoices", input);
82
82
  }
83
+ async signAndAuthorize(input) {
84
+ return this.request("POST", "/developer/sign-and-authorize", input);
85
+ }
86
+ async signOnly(input) {
87
+ return this.request("POST", "/developer/sign", input);
88
+ }
89
+ async validateXml(input) {
90
+ return this.request("POST", "/developer/validate-xml", input);
91
+ }
92
+ async verify(accessKey) {
93
+ return this.request("GET", `/developer/verify/${accessKey}`);
94
+ }
83
95
  async get(id) {
84
96
  return this.request("GET", `/developer/receipts/${id}`);
85
97
  }
@@ -116,6 +128,28 @@ var ProductsResource = class {
116
128
  }
117
129
  };
118
130
 
131
+ // src/resources/webhooks.ts
132
+ var WebhooksResource = class {
133
+ constructor(requester) {
134
+ this.request = requester;
135
+ }
136
+ /**
137
+ * Verify that a receipt (document) exists in the API.
138
+ * This is a second layer of verification beyond signature checking.
139
+ *
140
+ * @param receiptId - The receipt ID from the webhook payload
141
+ * @returns The receipt object if it exists, or `null` if not found
142
+ */
143
+ async verifyReceipt(receiptId) {
144
+ try {
145
+ const result = await this.request("GET", `/developer/receipts/${receiptId}`);
146
+ return result ?? null;
147
+ } catch {
148
+ return null;
149
+ }
150
+ }
151
+ };
152
+
119
153
  // src/client.ts
120
154
  var DEFAULT_BASE_URL = "https://api-rest.factuplan.com.ec/api/v1";
121
155
  var DEFAULT_TIMEOUT = 3e4;
@@ -129,6 +163,7 @@ var Factuplan = class {
129
163
  this.customers = new CustomersResource(requester);
130
164
  this.products = new ProductsResource(requester);
131
165
  this.invoices = new InvoicesResource(requester);
166
+ this.webhooks = new WebhooksResource(requester);
132
167
  }
133
168
  async usage() {
134
169
  return this.request("GET", "/developer/usage");
@@ -182,6 +217,7 @@ var Factuplan = class {
182
217
  return json;
183
218
  }
184
219
  };
220
+ Factuplan.webhooks = WebhooksResource;
185
221
  // Annotate the CommonJS export names for ESM import in node:
186
222
  0 && (module.exports = {
187
223
  AuthenticationError,
package/dist/index.mjs CHANGED
@@ -51,6 +51,18 @@ var InvoicesResource = class {
51
51
  async create(input) {
52
52
  return this.request("POST", "/developer/invoices", input);
53
53
  }
54
+ async signAndAuthorize(input) {
55
+ return this.request("POST", "/developer/sign-and-authorize", input);
56
+ }
57
+ async signOnly(input) {
58
+ return this.request("POST", "/developer/sign", input);
59
+ }
60
+ async validateXml(input) {
61
+ return this.request("POST", "/developer/validate-xml", input);
62
+ }
63
+ async verify(accessKey) {
64
+ return this.request("GET", `/developer/verify/${accessKey}`);
65
+ }
54
66
  async get(id) {
55
67
  return this.request("GET", `/developer/receipts/${id}`);
56
68
  }
@@ -87,6 +99,28 @@ var ProductsResource = class {
87
99
  }
88
100
  };
89
101
 
102
+ // src/resources/webhooks.ts
103
+ var WebhooksResource = class {
104
+ constructor(requester) {
105
+ this.request = requester;
106
+ }
107
+ /**
108
+ * Verify that a receipt (document) exists in the API.
109
+ * This is a second layer of verification beyond signature checking.
110
+ *
111
+ * @param receiptId - The receipt ID from the webhook payload
112
+ * @returns The receipt object if it exists, or `null` if not found
113
+ */
114
+ async verifyReceipt(receiptId) {
115
+ try {
116
+ const result = await this.request("GET", `/developer/receipts/${receiptId}`);
117
+ return result ?? null;
118
+ } catch {
119
+ return null;
120
+ }
121
+ }
122
+ };
123
+
90
124
  // src/client.ts
91
125
  var DEFAULT_BASE_URL = "https://api-rest.factuplan.com.ec/api/v1";
92
126
  var DEFAULT_TIMEOUT = 3e4;
@@ -100,6 +134,7 @@ var Factuplan = class {
100
134
  this.customers = new CustomersResource(requester);
101
135
  this.products = new ProductsResource(requester);
102
136
  this.invoices = new InvoicesResource(requester);
137
+ this.webhooks = new WebhooksResource(requester);
103
138
  }
104
139
  async usage() {
105
140
  return this.request("GET", "/developer/usage");
@@ -153,6 +188,7 @@ var Factuplan = class {
153
188
  return json;
154
189
  }
155
190
  };
191
+ Factuplan.webhooks = WebhooksResource;
156
192
  export {
157
193
  AuthenticationError,
158
194
  Factuplan,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "factuplan",
3
- "version": "0.2.1",
3
+ "version": "0.4.1",
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",
@@ -16,6 +16,7 @@
16
16
  "dist"
17
17
  ],
18
18
  "devDependencies": {
19
+ "@types/node": "^25.6.0",
19
20
  "tsup": "^8.0.0",
20
21
  "typescript": "^5.5.0"
21
22
  },