keycae-ts 1.0.0 β 1.2.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/LICENSE +21 -0
- package/README.md +174 -71
- package/dist/index.d.ts +180 -4
- package/dist/index.js +136 -10
- package/package.json +6 -1
- package/src/index.ts +300 -13
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 KeyCAE Software S.A.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,96 +1,199 @@
|
|
|
1
1
|
# keycae-ts π
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/keycae-ts)
|
|
4
|
+
[](https://www.npmjs.com/package/keycae-ts)
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
Cliente SDK oficial en **TypeScript** y **JavaScript** para interactuar con **KeyCAE.ar** y emitir facturaciΓ³n electrΓ³nica oficial ante **ARCA (ex AFIP)**.
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
## InstalaciΓ³n
|
|
8
10
|
|
|
9
11
|
```bash
|
|
10
12
|
npm install keycae-ts
|
|
11
|
-
# O usando yarn / pnpm
|
|
12
|
-
yarn add keycae-ts
|
|
13
|
-
pnpm add keycae-ts
|
|
14
13
|
```
|
|
15
14
|
|
|
16
|
-
## Inicio RΓ‘pido
|
|
15
|
+
## Inicio RΓ‘pido
|
|
16
|
+
|
|
17
|
+
El SDK soporta tanto el **Sandbox PΓΊblico** (sin cuenta, ideal para desarrollo rΓ‘pido) como el entorno de **ProducciΓ³n** (con cuenta registrada):
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
* **Para Probar en Sandbox (Sin Cuenta):** Usa la clave pΓΊblica `sk_test_public_sandbox_cuit_20999999999` y el CUIT de pruebas `20999999999`.
|
|
20
|
+
* **Para ProducciΓ³n (Con Cuenta):** RegΓstrate en [keycae.ar](https://keycae.ar) para obtener tu API Key `sk_live_...` y configura tu CUIT real.
|
|
19
21
|
|
|
20
22
|
```typescript
|
|
21
23
|
import { KeyCaeClient } from 'keycae-ts';
|
|
22
24
|
|
|
23
|
-
//
|
|
24
|
-
const client = new KeyCaeClient('
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
conceptos: [
|
|
48
|
-
{
|
|
49
|
-
descripcion: 'Servicios de ConsultorΓa de Software',
|
|
50
|
-
precio: 150000.00
|
|
51
|
-
}
|
|
52
|
-
]
|
|
53
|
-
}, 'idempotency_key_factura_42'); // Idempotency key para prevenir duplicaciones de red
|
|
54
|
-
|
|
55
|
-
console.log('Β‘Factura autorizada exitosamente!');
|
|
56
|
-
console.log(`Comprobante: Nro. ${invoice.numero_factura}`);
|
|
57
|
-
console.log(`CAE Otorgado: ${invoice.cae}`);
|
|
58
|
-
console.log(`Vencimiento CAE: ${invoice.cae_vencimiento}`);
|
|
59
|
-
console.log(`PDF de ImpresiΓ³n: ${invoice.url_pdf}`);
|
|
60
|
-
console.log(`CΓ³digo QR Fiscal: ${invoice.url_qr}`);
|
|
61
|
-
|
|
62
|
-
} catch (error) {
|
|
63
|
-
console.error('Error durante la operaciΓ³n:', error);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
main();
|
|
25
|
+
// Ejemplo para Sandbox PΓΊblico:
|
|
26
|
+
const client = new KeyCaeClient('sk_test_public_sandbox_cuit_20999999999');
|
|
27
|
+
// O para producciΓ³n: const client = new KeyCaeClient('sk_live_tu_api_key');
|
|
28
|
+
|
|
29
|
+
// Consultar contribuyente
|
|
30
|
+
const taxpayer = await client.getTaxpayer('20254459306');
|
|
31
|
+
console.log(`${taxpayer.nombre} | ${taxpayer.estado}`);
|
|
32
|
+
|
|
33
|
+
// Verificar quΓ© tipos de factura puede emitir
|
|
34
|
+
const capability = await client.checkEmissionCapability('20254459306');
|
|
35
|
+
console.log(`Tipos compatibles: ${capability.compatible_types.join(', ')}`);
|
|
36
|
+
console.log(capability.recommendation);
|
|
37
|
+
|
|
38
|
+
// Emitir factura
|
|
39
|
+
const invoice = await client.emitInvoice({
|
|
40
|
+
cuit_emisor: '20254459306',
|
|
41
|
+
punto_de_venta: 1,
|
|
42
|
+
tipo_comprobante: 'B',
|
|
43
|
+
receptor: { tipo_doc: 'CUIT', nro_doc: '20333444555' },
|
|
44
|
+
conceptos: [{ descripcion: 'Servicios', precio: 15000 }]
|
|
45
|
+
}, 'idempotency_key_42');
|
|
46
|
+
|
|
47
|
+
console.log(`CAE: ${invoice.cae}`);
|
|
48
|
+
console.log(`PDF: ${invoice.url_pdf}`);
|
|
68
49
|
```
|
|
69
50
|
|
|
70
|
-
|
|
51
|
+
### Precios netos (sin IVA)
|
|
71
52
|
|
|
72
|
-
|
|
53
|
+
Por defecto `conceptos[].precio` se envΓa con IVA incluido. Si tu sistema maneja precios netos, pasΓ‘ `iva_incluido: false` y KeyCAE calcula el IVA automΓ‘ticamente:
|
|
73
54
|
|
|
74
55
|
```typescript
|
|
75
|
-
|
|
56
|
+
const invoice = await client.emitInvoice({
|
|
57
|
+
cuit_emisor: '20254459306',
|
|
58
|
+
punto_de_venta: 1,
|
|
59
|
+
tipo_comprobante: 'A',
|
|
60
|
+
iva_incluido: false, // conceptos[].precio son netos
|
|
61
|
+
receptor: { tipo_doc: 'CUIT', nro_doc: '30999888776' },
|
|
62
|
+
conceptos: [{ descripcion: 'Servicio profesional', precio: 1000, alicuota_iva: 21 }]
|
|
63
|
+
}, 'idempotency_key_43');
|
|
64
|
+
// β Neto $1.000 | IVA 21% $210 | Total $1.210
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Modelos de ConexiΓ³n
|
|
68
|
+
|
|
69
|
+
### Modalidad A: DelegaciΓ³n Directa (Recomendada)
|
|
70
|
+
Sin certificados, sin llaves privadas. En minutos facturΓ‘s.
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
const delegation = await client.createDelegation({
|
|
74
|
+
cuit: '20254459306',
|
|
75
|
+
organization: 'Tu Empresa'
|
|
76
|
+
});
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Modalidad B: BΓ³vedas KMS
|
|
80
|
+
GeneraciΓ³n segura de claves RSA y CSR.
|
|
76
81
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
82
|
+
```typescript
|
|
83
|
+
const credential = await client.createCredential({
|
|
84
|
+
cuit: '20254459306',
|
|
85
|
+
organization: 'Tu Empresa'
|
|
86
|
+
});
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Modalidad C: Importar Certificado
|
|
90
|
+
Subida directa de certificados (.crt) y llaves (.key).
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
await client.importCredential({
|
|
94
|
+
cuit: '20254459306',
|
|
95
|
+
organization: 'Tu Empresa',
|
|
96
|
+
certificate: certificatePem,
|
|
97
|
+
private_key: privateKeyPem
|
|
98
|
+
});
|
|
92
99
|
```
|
|
93
100
|
|
|
101
|
+
## MΓ©todos Disponibles
|
|
102
|
+
|
|
103
|
+
### Taxpayers
|
|
104
|
+
| MΓ©todo | DescripciΓ³n |
|
|
105
|
+
|--------|-------------|
|
|
106
|
+
| `getTaxpayer(cuit)` | Consultar contribuyente en padrΓ³n ARCA |
|
|
107
|
+
| `checkEmissionCapability(cuit)` | Verificar tipos de factura compatibles |
|
|
108
|
+
|
|
109
|
+
### Delegations
|
|
110
|
+
| MΓ©todo | DescripciΓ³n |
|
|
111
|
+
|--------|-------------|
|
|
112
|
+
| `createDelegation(data)` | Iniciar delegaciΓ³n directa |
|
|
113
|
+
| `checkDelegationStatus()` | Consultar estado de delegaciΓ³n |
|
|
114
|
+
|
|
115
|
+
### Credentials (KMS)
|
|
116
|
+
| MΓ©todo | DescripciΓ³n |
|
|
117
|
+
|--------|-------------|
|
|
118
|
+
| `createCredential(data)` | Generar RSA keypair + CSR |
|
|
119
|
+
| `listCredentials()` | Listar certificados registrados |
|
|
120
|
+
| `importCredential(data)` | Importar certificado existente |
|
|
121
|
+
| `activateCredential(id, cert)` | Activar bΓ³veda con certificado ARCA |
|
|
122
|
+
| `deleteCredential(id)` | Eliminar bΓ³veda de claves |
|
|
123
|
+
|
|
124
|
+
### Invoices
|
|
125
|
+
| MΓ©todo | DescripciΓ³n |
|
|
126
|
+
|--------|-------------|
|
|
127
|
+
| `emitInvoice(data, idempotencyKey?)` | Emitir factura electrΓ³nica (CAE) |
|
|
128
|
+
| `getInvoice(id)` | Obtener detalles de factura |
|
|
129
|
+
| `listInvoices(limit?, offset?)` | Listar facturas recientes |
|
|
130
|
+
| `getInvoicePdfBuffer(id)` | Descargar PDF de factura |
|
|
131
|
+
|
|
132
|
+
### Puntos de Venta
|
|
133
|
+
| MΓ©todo | DescripciΓ³n |
|
|
134
|
+
|--------|-------------|
|
|
135
|
+
| `listPuntosDeVenta()` | Listar puntos de venta habilitados |
|
|
136
|
+
|
|
137
|
+
### Billing & Settings
|
|
138
|
+
| MΓ©todo | DescripciΓ³n |
|
|
139
|
+
|--------|-------------|
|
|
140
|
+
| `getBillingStatus()` | Estado del plan y consumo |
|
|
141
|
+
| `getTelegramSettings()` | Obtener configuraciΓ³n Telegram |
|
|
142
|
+
| `saveTelegramSettings(data)` | Guardar configuraciΓ³n Telegram |
|
|
143
|
+
| `health()` | Health check de la API |
|
|
144
|
+
|
|
145
|
+
### Partners (ERPs / SaaS)
|
|
146
|
+
| MΓ©todo | DescripciΓ³n |
|
|
147
|
+
|--------|-------------|
|
|
148
|
+
| `createPartnerSubaccount(data)` | Crear subcuenta completa para un cliente final (usuario + API Key) |
|
|
149
|
+
| `listPartnerSubaccounts()` | Listar tus clientes con plan y consumo mensual |
|
|
150
|
+
| `preauthorizeCuit(cuit)` | Pre-autorizar un CUIT para facturaciΓ³n consolidada |
|
|
151
|
+
| `getPartnerConfig(partnerId)` | ConfiguraciΓ³n pΓΊblica de co-branding (sin auth) |
|
|
152
|
+
|
|
153
|
+
> Los mΓ©todos de Partners requieren instanciar el cliente con tu **API Key de Partner** (`sk_partner_live_...`) y solo deben usarse desde tu backend:
|
|
154
|
+
>
|
|
155
|
+
> ```typescript
|
|
156
|
+
> const partnerClient = new KeyCaeClient('sk_partner_live_mi-erp_...');
|
|
157
|
+
>
|
|
158
|
+
> const sub = await partnerClient.createPartnerSubaccount({
|
|
159
|
+
> cuit: '20304567891',
|
|
160
|
+
> organization: 'Cliente S.A.',
|
|
161
|
+
> email: 'cliente@empresa.com'
|
|
162
|
+
> });
|
|
163
|
+
> // sub.api_key y sub.password se devuelven UNA sola vez
|
|
164
|
+
>
|
|
165
|
+
> const { clients, total } = await partnerClient.listPartnerSubaccounts();
|
|
166
|
+
> ```
|
|
167
|
+
>
|
|
168
|
+
> π GuΓa completa del programa de partners: [keycae.ar/docs/partners.md](https://keycae.ar/docs/partners.md)
|
|
169
|
+
|
|
170
|
+
## Tipos de Comprobante
|
|
171
|
+
|
|
172
|
+
| Tipo | DescripciΓ³n |
|
|
173
|
+
|------|-------------|
|
|
174
|
+
| `A` | IVA discriminado (Responsable Inscripto β RI) |
|
|
175
|
+
| `B` | Consumidor Final (RI β CF) |
|
|
176
|
+
| `C` | Exento (Monotributo / Exento) |
|
|
177
|
+
| `M` | Monotributo |
|
|
178
|
+
| `E` | ExportaciΓ³n |
|
|
179
|
+
| `NCA` `NCB` `NCC` `NCE` `NCM` | Notas de CrΓ©dito (A, B, C, E, M) |
|
|
180
|
+
| `NDA` `NDB` `NDC` `NDE` `NDM` | Notas de DΓ©bito (A, B, C, E, M) |
|
|
181
|
+
|
|
182
|
+
## Alertas Telegram
|
|
183
|
+
|
|
184
|
+
```typescript
|
|
185
|
+
await client.saveTelegramSettings({
|
|
186
|
+
telegram_bot_token: '123456:***',
|
|
187
|
+
telegram_chat_id: '987654321'
|
|
188
|
+
});
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## DocumentaciΓ³n
|
|
192
|
+
|
|
193
|
+
- π [docs.keycae.ar](https://docs.keycae.ar) β DocumentaciΓ³n interactiva
|
|
194
|
+
- π [llms.txt](https://keycae.ar/llms.txt) β Para AI agents
|
|
195
|
+
- π [MCP Server](https://www.npmjs.com/package/keycae-mcp) β Para Cursor/Claude
|
|
196
|
+
|
|
94
197
|
## Licencia
|
|
95
198
|
|
|
96
199
|
MIT
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
export interface DomicilioFiscal {
|
|
2
|
+
direccion: string | null;
|
|
3
|
+
localidad: string | null;
|
|
4
|
+
cod_postal: string | null;
|
|
5
|
+
provincia: string | null;
|
|
6
|
+
}
|
|
1
7
|
export interface TaxpayerResponse {
|
|
2
8
|
cuit: string;
|
|
3
9
|
nombre: string;
|
|
@@ -5,23 +11,70 @@ export interface TaxpayerResponse {
|
|
|
5
11
|
categoria_monotributo?: string;
|
|
6
12
|
es_iva_inscripto: boolean;
|
|
7
13
|
estado: string;
|
|
14
|
+
condicion_iva?: string;
|
|
15
|
+
actividades?: string[];
|
|
16
|
+
domicilio_fiscal?: DomicilioFiscal;
|
|
8
17
|
}
|
|
9
18
|
export interface InvoiceReceptor {
|
|
10
|
-
tipo_doc: 'DNI' | 'CUIT' | 'CUIL' | 'PASAPORTE';
|
|
19
|
+
tipo_doc: 'DNI' | 'CUIT' | 'CUIL' | 'PASAPORTE' | 'SIN_IDENTIFICAR';
|
|
11
20
|
nro_doc: string;
|
|
21
|
+
razon_social?: string;
|
|
22
|
+
condicion_iva?: string;
|
|
12
23
|
}
|
|
13
24
|
export interface InvoiceItem {
|
|
14
25
|
descripcion: string;
|
|
15
26
|
precio: number;
|
|
27
|
+
cantidad?: number;
|
|
28
|
+
alicuota_iva?: number;
|
|
29
|
+
}
|
|
30
|
+
export interface Tributo {
|
|
31
|
+
id: number;
|
|
32
|
+
descripcion: string;
|
|
33
|
+
base_imponible: number;
|
|
34
|
+
alicuota: number;
|
|
35
|
+
importe: number;
|
|
36
|
+
}
|
|
37
|
+
export interface Opcional {
|
|
38
|
+
id: string;
|
|
39
|
+
valor: string;
|
|
40
|
+
}
|
|
41
|
+
export interface CondicionesIvaResponse {
|
|
42
|
+
condiciones: {
|
|
43
|
+
codigo: number;
|
|
44
|
+
nombre: string;
|
|
45
|
+
}[];
|
|
16
46
|
}
|
|
17
47
|
export interface InvoiceInput {
|
|
18
48
|
cuit_emisor: string;
|
|
19
49
|
punto_de_venta: number;
|
|
20
|
-
tipo_comprobante: 'A' | 'B' | 'C' | 'M';
|
|
50
|
+
tipo_comprobante: 'A' | 'B' | 'C' | 'M' | 'E' | 'NCA' | 'NCB' | 'NCC' | 'NCE' | 'NCM' | 'NDA' | 'NDB' | 'NDC' | 'NDE' | 'NDM' | 'FCE_A' | 'FCE_B' | 'FCE_C' | 'FCE_NDA' | 'FCE_NDB' | 'FCE_NDC' | 'FCE_NCA' | 'FCE_NCB' | 'FCE_NCC';
|
|
21
51
|
receptor: InvoiceReceptor;
|
|
22
52
|
conceptos: InvoiceItem[];
|
|
53
|
+
/**
|
|
54
|
+
* Default `true`: los `conceptos[].precio` se envΓan con IVA incluido (precio final).
|
|
55
|
+
* Con `false`, los precios se interpretan como netos (sin IVA) y KeyCAE calcula
|
|
56
|
+
* y adiciona el IVA segΓΊn la `alicuota_iva` de cada Γtem.
|
|
57
|
+
* Sin efecto en comprobantes sin discriminaciΓ³n de IVA (tipo C / E).
|
|
58
|
+
*/
|
|
59
|
+
iva_incluido?: boolean;
|
|
60
|
+
tributos?: Tributo[];
|
|
61
|
+
moneda?: string;
|
|
62
|
+
moneda_cotizacion?: number;
|
|
63
|
+
fecha_comprobante?: string;
|
|
64
|
+
fecha_servicio_desde?: string;
|
|
65
|
+
fecha_servicio_hasta?: string;
|
|
66
|
+
fecha_vto_pago?: string;
|
|
67
|
+
condicion_iva_receptor?: number;
|
|
68
|
+
opcionales?: Opcional[];
|
|
23
69
|
brand_logo_url?: string;
|
|
24
70
|
brand_color?: string;
|
|
71
|
+
cbtes_asociados?: {
|
|
72
|
+
tipo: string | number;
|
|
73
|
+
punto_de_venta: number;
|
|
74
|
+
numero: number;
|
|
75
|
+
cuit?: string;
|
|
76
|
+
fecha?: string;
|
|
77
|
+
}[];
|
|
25
78
|
}
|
|
26
79
|
export interface InvoiceResponse {
|
|
27
80
|
id: string;
|
|
@@ -61,7 +114,7 @@ export interface DelegationInput {
|
|
|
61
114
|
}
|
|
62
115
|
export interface DelegationResponse {
|
|
63
116
|
id: string;
|
|
64
|
-
status: 'pending' | 'accepted' | 'rejected';
|
|
117
|
+
status: 'pending' | 'accepted' | 'rejected' | 'pending_auto';
|
|
65
118
|
cuit: string;
|
|
66
119
|
organization: string;
|
|
67
120
|
representativeCuit: string;
|
|
@@ -89,6 +142,70 @@ export interface KmsImportInput {
|
|
|
89
142
|
certificate: string;
|
|
90
143
|
private_key: string;
|
|
91
144
|
}
|
|
145
|
+
export interface PuntoDeVenta {
|
|
146
|
+
numero: number;
|
|
147
|
+
tipoEmision: string;
|
|
148
|
+
tipoAutomatizacion?: string;
|
|
149
|
+
fechaServicioDesde?: string;
|
|
150
|
+
fechaServicioHasta?: string;
|
|
151
|
+
}
|
|
152
|
+
export interface EmissionCapability {
|
|
153
|
+
cuit: string;
|
|
154
|
+
condicion_iva: string;
|
|
155
|
+
compatible_types: string[];
|
|
156
|
+
recommendation: string;
|
|
157
|
+
tip: string;
|
|
158
|
+
}
|
|
159
|
+
export interface HealthResponse {
|
|
160
|
+
status: string;
|
|
161
|
+
version?: string;
|
|
162
|
+
uptime?: number;
|
|
163
|
+
}
|
|
164
|
+
export interface PartnerSubaccountInput {
|
|
165
|
+
/** CUIT fiscal del cliente final (11 dΓgitos, sin guiones) */
|
|
166
|
+
cuit: string;
|
|
167
|
+
/** RazΓ³n social del cliente final */
|
|
168
|
+
organization: string;
|
|
169
|
+
/** Email de acceso del cliente final */
|
|
170
|
+
email: string;
|
|
171
|
+
}
|
|
172
|
+
export interface PartnerSubaccountResponse {
|
|
173
|
+
id: string;
|
|
174
|
+
cuit: string;
|
|
175
|
+
organization: string;
|
|
176
|
+
email: string;
|
|
177
|
+
/** ContraseΓ±a generada β se devuelve UNA sola vez. Entregar por canal seguro. */
|
|
178
|
+
password: string;
|
|
179
|
+
/** API Key live de la subcuenta β se devuelve UNA sola vez. */
|
|
180
|
+
api_key: string;
|
|
181
|
+
partner_id: string;
|
|
182
|
+
}
|
|
183
|
+
export interface PartnerClient {
|
|
184
|
+
cuit: string;
|
|
185
|
+
organization: string;
|
|
186
|
+
email: string;
|
|
187
|
+
plan: 'free' | 'developer' | 'platform';
|
|
188
|
+
invoices_this_month: number;
|
|
189
|
+
created_at: string | null;
|
|
190
|
+
}
|
|
191
|
+
export interface PartnerClientsResponse {
|
|
192
|
+
partner_id: string;
|
|
193
|
+
total: number;
|
|
194
|
+
clients: PartnerClient[];
|
|
195
|
+
}
|
|
196
|
+
export interface PartnerPreauthResponse {
|
|
197
|
+
success: boolean;
|
|
198
|
+
message: string;
|
|
199
|
+
partner_id: string;
|
|
200
|
+
cuit: string;
|
|
201
|
+
}
|
|
202
|
+
export interface PartnerPublicConfig {
|
|
203
|
+
id: string;
|
|
204
|
+
name: string;
|
|
205
|
+
logo_url: string;
|
|
206
|
+
brand_color: string;
|
|
207
|
+
billing_mode: 'decentralized' | 'consolidated';
|
|
208
|
+
}
|
|
92
209
|
export declare class KeyCaeClient {
|
|
93
210
|
private apiKey;
|
|
94
211
|
private baseUrl;
|
|
@@ -98,6 +215,10 @@ export declare class KeyCaeClient {
|
|
|
98
215
|
* Consultar Contribuyente en PadrΓ³n ARCA
|
|
99
216
|
*/
|
|
100
217
|
getTaxpayer(cuit: string): Promise<TaxpayerResponse>;
|
|
218
|
+
/**
|
|
219
|
+
* Verificar quΓ© tipos de factura puede emitir un CUIT segΓΊn su condiciΓ³n fiscal
|
|
220
|
+
*/
|
|
221
|
+
checkEmissionCapability(cuit: string): Promise<EmissionCapability>;
|
|
101
222
|
/**
|
|
102
223
|
* Registrar / Iniciar Direct Delegation
|
|
103
224
|
*/
|
|
@@ -110,6 +231,10 @@ export declare class KeyCaeClient {
|
|
|
110
231
|
* Crear BΓ³veda de Claves KMS & Generar CSR
|
|
111
232
|
*/
|
|
112
233
|
createCredential(data: KmsCredentialInput): Promise<KmsCredentialResponse>;
|
|
234
|
+
/**
|
|
235
|
+
* Listar Credenciales Digitales Registradas
|
|
236
|
+
*/
|
|
237
|
+
listCredentials(): Promise<KmsCredentialResponse[]>;
|
|
113
238
|
/**
|
|
114
239
|
* Importar Credenciales de Firma Existentes (.key y .crt)
|
|
115
240
|
*/
|
|
@@ -126,10 +251,27 @@ export declare class KeyCaeClient {
|
|
|
126
251
|
* Emitir Factura ElectrΓ³nica Homologada (CAE)
|
|
127
252
|
*/
|
|
128
253
|
emitInvoice(data: InvoiceInput, idempotencyKey?: string): Promise<InvoiceResponse>;
|
|
254
|
+
/**
|
|
255
|
+
* Obtener Detalles de una Factura por ID
|
|
256
|
+
*/
|
|
257
|
+
getInvoice(id: string): Promise<InvoiceResponse>;
|
|
258
|
+
/**
|
|
259
|
+
* Listar Facturas Recientes
|
|
260
|
+
*/
|
|
261
|
+
listInvoices(limit?: number, offset?: number): Promise<{
|
|
262
|
+
invoices: InvoiceResponse[];
|
|
263
|
+
total: number;
|
|
264
|
+
}>;
|
|
129
265
|
/**
|
|
130
266
|
* Descargar PDF de Factura (Retorna el Stream / ArrayBuffer)
|
|
131
267
|
*/
|
|
132
|
-
getInvoicePdfBuffer(id: string
|
|
268
|
+
getInvoicePdfBuffer(id: string, options?: {
|
|
269
|
+
format?: 'a4' | 'ticket';
|
|
270
|
+
}): Promise<Buffer>;
|
|
271
|
+
/**
|
|
272
|
+
* Listar Puntos de Venta Habilitados para FacturaciΓ³n ElectrΓ³nica
|
|
273
|
+
*/
|
|
274
|
+
listPuntosDeVenta(): Promise<PuntoDeVenta[]>;
|
|
133
275
|
/**
|
|
134
276
|
* Obtener Consumos y Estado del Plan (Billing)
|
|
135
277
|
*/
|
|
@@ -142,4 +284,38 @@ export declare class KeyCaeClient {
|
|
|
142
284
|
* Guardar / Actualizar Ajustes de Telegram
|
|
143
285
|
*/
|
|
144
286
|
saveTelegramSettings(data: TelegramSettingsInput): Promise<any>;
|
|
287
|
+
/**
|
|
288
|
+
* Health Check de la API
|
|
289
|
+
*/
|
|
290
|
+
health(): Promise<HealthResponse>;
|
|
291
|
+
/**
|
|
292
|
+
* Obtener tabla de condiciones IVA del receptor (15 cΓ³digos oficiales ARCA)
|
|
293
|
+
*/
|
|
294
|
+
getCondicionesIva(): Promise<CondicionesIvaResponse>;
|
|
295
|
+
/**
|
|
296
|
+
* Consultar cotizaciΓ³n de una moneda extranjera vs peso (vΓa ARCA)
|
|
297
|
+
*/
|
|
298
|
+
getCotizacionMoneda(moneda: string): Promise<{
|
|
299
|
+
moneda: string;
|
|
300
|
+
cotizacion: number;
|
|
301
|
+
}>;
|
|
302
|
+
/**
|
|
303
|
+
* Crear una subcuenta completa (usuario + perfil + API Key) para un
|
|
304
|
+
* cliente final de tu ERP. La password y api_key se devuelven una sola vez.
|
|
305
|
+
*/
|
|
306
|
+
createPartnerSubaccount(data: PartnerSubaccountInput): Promise<PartnerSubaccountResponse>;
|
|
307
|
+
/**
|
|
308
|
+
* Listar los clientes vinculados a tu partner, con plan y consumo mensual.
|
|
309
|
+
*/
|
|
310
|
+
listPartnerSubaccounts(): Promise<PartnerClientsResponse>;
|
|
311
|
+
/**
|
|
312
|
+
* Pre-autorizar el CUIT de un cliente para facturaciΓ³n consolidada
|
|
313
|
+
* (el cliente no pasarΓ‘ por la pasarela de pago al registrarse).
|
|
314
|
+
*/
|
|
315
|
+
preauthorizeCuit(cuit: string): Promise<PartnerPreauthResponse>;
|
|
316
|
+
/**
|
|
317
|
+
* Consultar la configuraciΓ³n pΓΊblica de co-branding de un partner
|
|
318
|
+
* (endpoint pΓΊblico β no requiere autenticaciΓ³n).
|
|
319
|
+
*/
|
|
320
|
+
getPartnerConfig(partnerId: string): Promise<PartnerPublicConfig>;
|
|
145
321
|
}
|
package/dist/index.js
CHANGED
|
@@ -5,10 +5,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.KeyCaeClient = void 0;
|
|
7
7
|
const node_fetch_1 = __importDefault(require("node-fetch"));
|
|
8
|
+
// ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
9
|
+
// CLIENT
|
|
10
|
+
// ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
8
11
|
class KeyCaeClient {
|
|
9
|
-
constructor(apiKey, baseUrl = 'https://
|
|
12
|
+
constructor(apiKey, baseUrl = 'https://keycae.ar') {
|
|
10
13
|
this.apiKey = apiKey;
|
|
11
|
-
this.baseUrl = baseUrl;
|
|
14
|
+
this.baseUrl = baseUrl.replace(/\/$/, '');
|
|
12
15
|
}
|
|
13
16
|
async request(method, path, body, idempotencyKey) {
|
|
14
17
|
const headers = {
|
|
@@ -24,21 +27,60 @@ class KeyCaeClient {
|
|
|
24
27
|
body: body ? JSON.stringify(body) : undefined
|
|
25
28
|
});
|
|
26
29
|
if (!response.ok) {
|
|
27
|
-
let
|
|
30
|
+
let errorData;
|
|
28
31
|
try {
|
|
29
|
-
|
|
32
|
+
errorData = await response.json();
|
|
30
33
|
}
|
|
31
|
-
catch
|
|
32
|
-
|
|
34
|
+
catch {
|
|
35
|
+
const text = await response.text().catch(() => '');
|
|
36
|
+
throw new Error(`KeyCAE API Error (${response.status}): ${text || response.statusText}`);
|
|
37
|
+
}
|
|
38
|
+
const message = errorData?.error?.message || JSON.stringify(errorData);
|
|
39
|
+
const hint = errorData?.error?.ai_action_hint || '';
|
|
40
|
+
throw new Error(`KeyCAE API Error (${response.status}): ${message}${hint ? ` [hint: ${hint}]` : ''}`);
|
|
33
41
|
}
|
|
34
42
|
return response.json();
|
|
35
43
|
}
|
|
44
|
+
// ββ Taxpayers βββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
36
45
|
/**
|
|
37
46
|
* Consultar Contribuyente en PadrΓ³n ARCA
|
|
38
47
|
*/
|
|
39
48
|
async getTaxpayer(cuit) {
|
|
40
49
|
return this.request('GET', `/v1/taxpayers/${cuit}`);
|
|
41
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* Verificar quΓ© tipos de factura puede emitir un CUIT segΓΊn su condiciΓ³n fiscal
|
|
53
|
+
*/
|
|
54
|
+
async checkEmissionCapability(cuit) {
|
|
55
|
+
const taxpayer = await this.getTaxpayer(cuit);
|
|
56
|
+
const condition = taxpayer.condicion_iva || taxpayer.estado || '';
|
|
57
|
+
let compatibleTypes = [];
|
|
58
|
+
let recommendation = '';
|
|
59
|
+
if (condition.toLowerCase().includes('monotributo')) {
|
|
60
|
+
compatibleTypes = ['C', 'M'];
|
|
61
|
+
recommendation = 'Como Monotributista, podΓ©s emitir Factura C (exenta) o Factura M (monotributo). NO podΓ©s emitir Factura A o B.';
|
|
62
|
+
}
|
|
63
|
+
else if (condition.toLowerCase().includes('responsable inscripto') || condition.toLowerCase().includes('ri')) {
|
|
64
|
+
compatibleTypes = ['A', 'B'];
|
|
65
|
+
recommendation = 'Como Responsable Inscripto, podΓ©s emitir Factura A (IVA discriminado) o Factura B (consumidor final).';
|
|
66
|
+
}
|
|
67
|
+
else if (condition.toLowerCase().includes('exento')) {
|
|
68
|
+
compatibleTypes = ['C'];
|
|
69
|
+
recommendation = 'Como Exento, solo podΓ©s emitir Factura C (exenta).';
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
compatibleTypes = ['C'];
|
|
73
|
+
recommendation = 'No se pudo determinar la condiciΓ³n impositiva. Se recomienda Factura C por defecto.';
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
cuit,
|
|
77
|
+
condicion_iva: condition,
|
|
78
|
+
compatible_types: compatibleTypes,
|
|
79
|
+
recommendation,
|
|
80
|
+
tip: 'UsΓ‘ estos tipos al emitir facturas con emitInvoice para evitar errores de ARCA.'
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
// ββ Delegations βββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
42
84
|
/**
|
|
43
85
|
* Registrar / Iniciar Direct Delegation
|
|
44
86
|
*/
|
|
@@ -51,12 +93,19 @@ class KeyCaeClient {
|
|
|
51
93
|
async checkDelegationStatus() {
|
|
52
94
|
return this.request('GET', '/v1/delegations/status');
|
|
53
95
|
}
|
|
96
|
+
// ββ Credentials (KMS) ββββββββββββββββββββββββββββββββββββββββββββ
|
|
54
97
|
/**
|
|
55
98
|
* Crear BΓ³veda de Claves KMS & Generar CSR
|
|
56
99
|
*/
|
|
57
100
|
async createCredential(data) {
|
|
58
101
|
return this.request('POST', '/v1/credentials', data);
|
|
59
102
|
}
|
|
103
|
+
/**
|
|
104
|
+
* Listar Credenciales Digitales Registradas
|
|
105
|
+
*/
|
|
106
|
+
async listCredentials() {
|
|
107
|
+
return this.request('GET', '/v1/credentials');
|
|
108
|
+
}
|
|
60
109
|
/**
|
|
61
110
|
* Importar Credenciales de Firma Existentes (.key y .crt)
|
|
62
111
|
*/
|
|
@@ -75,17 +124,35 @@ class KeyCaeClient {
|
|
|
75
124
|
async deleteCredential(id) {
|
|
76
125
|
return this.request('DELETE', `/v1/credentials/${id}`);
|
|
77
126
|
}
|
|
127
|
+
// ββ Invoices ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
78
128
|
/**
|
|
79
129
|
* Emitir Factura ElectrΓ³nica Homologada (CAE)
|
|
80
130
|
*/
|
|
81
131
|
async emitInvoice(data, idempotencyKey) {
|
|
82
132
|
return this.request('POST', '/v1/invoices', data, idempotencyKey);
|
|
83
133
|
}
|
|
134
|
+
/**
|
|
135
|
+
* Obtener Detalles de una Factura por ID
|
|
136
|
+
*/
|
|
137
|
+
async getInvoice(id) {
|
|
138
|
+
return this.request('GET', `/v1/invoices/${id}`);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Listar Facturas Recientes
|
|
142
|
+
*/
|
|
143
|
+
async listInvoices(limit = 10, offset = 0) {
|
|
144
|
+
const params = new URLSearchParams({ limit: String(limit), offset: String(offset) });
|
|
145
|
+
return this.request('GET', `/v1/invoices?${params}`);
|
|
146
|
+
}
|
|
84
147
|
/**
|
|
85
148
|
* Descargar PDF de Factura (Retorna el Stream / ArrayBuffer)
|
|
86
149
|
*/
|
|
87
|
-
async getInvoicePdfBuffer(id) {
|
|
88
|
-
const
|
|
150
|
+
async getInvoicePdfBuffer(id, options) {
|
|
151
|
+
const url = new URL(`${this.baseUrl}/v1/invoices/${id}/pdf`);
|
|
152
|
+
if (options?.format) {
|
|
153
|
+
url.searchParams.append('format', options.format);
|
|
154
|
+
}
|
|
155
|
+
const response = await (0, node_fetch_1.default)(url.toString(), {
|
|
89
156
|
method: 'GET',
|
|
90
157
|
headers: {
|
|
91
158
|
'Authorization': `Bearer ${this.apiKey}`
|
|
@@ -94,15 +161,23 @@ class KeyCaeClient {
|
|
|
94
161
|
if (!response.ok) {
|
|
95
162
|
throw new Error(`Failed to fetch PDF (${response.status})`);
|
|
96
163
|
}
|
|
97
|
-
|
|
98
|
-
|
|
164
|
+
return Buffer.from(await response.arrayBuffer());
|
|
165
|
+
}
|
|
166
|
+
// ββ Puntos de Venta βββββββββββββββββββββββββββββββββββββββββββββββ
|
|
167
|
+
/**
|
|
168
|
+
* Listar Puntos de Venta Habilitados para FacturaciΓ³n ElectrΓ³nica
|
|
169
|
+
*/
|
|
170
|
+
async listPuntosDeVenta() {
|
|
171
|
+
return this.request('GET', '/v1/pos');
|
|
99
172
|
}
|
|
173
|
+
// ββ Billing βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
100
174
|
/**
|
|
101
175
|
* Obtener Consumos y Estado del Plan (Billing)
|
|
102
176
|
*/
|
|
103
177
|
async getBillingStatus() {
|
|
104
178
|
return this.request('GET', '/v1/billing/status');
|
|
105
179
|
}
|
|
180
|
+
// ββ Telegram Settings βββββββββββββββββββββββββββββββββββββββββββββ
|
|
106
181
|
/**
|
|
107
182
|
* Obtener Ajustes de Telegram por Tenant
|
|
108
183
|
*/
|
|
@@ -115,5 +190,56 @@ class KeyCaeClient {
|
|
|
115
190
|
async saveTelegramSettings(data) {
|
|
116
191
|
return this.request('POST', '/v1/settings/telegram', data);
|
|
117
192
|
}
|
|
193
|
+
// ββ Health ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
194
|
+
/**
|
|
195
|
+
* Health Check de la API
|
|
196
|
+
*/
|
|
197
|
+
async health() {
|
|
198
|
+
return this.request('GET', '/health');
|
|
199
|
+
}
|
|
200
|
+
// ββ CondiciΓ³n IVA Receptor ββββββββββββββββββββββββββββββββββββββ
|
|
201
|
+
/**
|
|
202
|
+
* Obtener tabla de condiciones IVA del receptor (15 cΓ³digos oficiales ARCA)
|
|
203
|
+
*/
|
|
204
|
+
async getCondicionesIva() {
|
|
205
|
+
return this.request('GET', '/v1/taxpayers/condiciones-iva');
|
|
206
|
+
}
|
|
207
|
+
// ββ CotizaciΓ³n de Moneda ββββββββββββββββββββββββββββββββββββββββ
|
|
208
|
+
/**
|
|
209
|
+
* Consultar cotizaciΓ³n de una moneda extranjera vs peso (vΓa ARCA)
|
|
210
|
+
*/
|
|
211
|
+
async getCotizacionMoneda(moneda) {
|
|
212
|
+
return this.request('GET', `/v1/cotizacion/${moneda}`);
|
|
213
|
+
}
|
|
214
|
+
// ββ Partners (ERP / SaaS) ββββββββββββββββββββββββββββββββββββββββ
|
|
215
|
+
// Estos mΓ©todos requieren instanciar el cliente con tu API Key de
|
|
216
|
+
// Partner (sk_partner_live_...) β solo desde tu backend.
|
|
217
|
+
/**
|
|
218
|
+
* Crear una subcuenta completa (usuario + perfil + API Key) para un
|
|
219
|
+
* cliente final de tu ERP. La password y api_key se devuelven una sola vez.
|
|
220
|
+
*/
|
|
221
|
+
async createPartnerSubaccount(data) {
|
|
222
|
+
return this.request('POST', '/v1/partners/subaccounts', data);
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Listar los clientes vinculados a tu partner, con plan y consumo mensual.
|
|
226
|
+
*/
|
|
227
|
+
async listPartnerSubaccounts() {
|
|
228
|
+
return this.request('GET', '/v1/partners/subaccounts');
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Pre-autorizar el CUIT de un cliente para facturaciΓ³n consolidada
|
|
232
|
+
* (el cliente no pasarΓ‘ por la pasarela de pago al registrarse).
|
|
233
|
+
*/
|
|
234
|
+
async preauthorizeCuit(cuit) {
|
|
235
|
+
return this.request('POST', '/v1/partners/preauthorize', { cuit });
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Consultar la configuraciΓ³n pΓΊblica de co-branding de un partner
|
|
239
|
+
* (endpoint pΓΊblico β no requiere autenticaciΓ³n).
|
|
240
|
+
*/
|
|
241
|
+
async getPartnerConfig(partnerId) {
|
|
242
|
+
return this.request('GET', `/v1/partners/${encodeURIComponent(partnerId)}/config`);
|
|
243
|
+
}
|
|
118
244
|
}
|
|
119
245
|
exports.KeyCaeClient = KeyCaeClient;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "keycae-ts",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Official TypeScript & JavaScript SDK client for KeyCAE.ar impositive compliance API (ARCA)",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -20,6 +20,11 @@
|
|
|
20
20
|
],
|
|
21
21
|
"author": "KeyCAE Community",
|
|
22
22
|
"license": "MIT",
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "https://github.com/AMKRS3/keycae-packages",
|
|
26
|
+
"directory": "keycae-ts"
|
|
27
|
+
},
|
|
23
28
|
"dependencies": {
|
|
24
29
|
"node-fetch": "^2.6.9"
|
|
25
30
|
},
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
import fetch from 'node-fetch';
|
|
2
2
|
|
|
3
|
+
// ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
4
|
+
// INTERFACES
|
|
5
|
+
// ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
6
|
+
|
|
7
|
+
export interface DomicilioFiscal {
|
|
8
|
+
direccion: string | null;
|
|
9
|
+
localidad: string | null;
|
|
10
|
+
cod_postal: string | null;
|
|
11
|
+
provincia: string | null;
|
|
12
|
+
}
|
|
13
|
+
|
|
3
14
|
export interface TaxpayerResponse {
|
|
4
15
|
cuit: string;
|
|
5
16
|
nombre: string;
|
|
@@ -7,26 +18,78 @@ export interface TaxpayerResponse {
|
|
|
7
18
|
categoria_monotributo?: string;
|
|
8
19
|
es_iva_inscripto: boolean;
|
|
9
20
|
estado: string;
|
|
21
|
+
condicion_iva?: string;
|
|
22
|
+
actividades?: string[];
|
|
23
|
+
domicilio_fiscal?: DomicilioFiscal;
|
|
10
24
|
}
|
|
11
25
|
|
|
12
26
|
export interface InvoiceReceptor {
|
|
13
|
-
tipo_doc: 'DNI' | 'CUIT' | 'CUIL' | 'PASAPORTE';
|
|
27
|
+
tipo_doc: 'DNI' | 'CUIT' | 'CUIL' | 'PASAPORTE' | 'SIN_IDENTIFICAR';
|
|
14
28
|
nro_doc: string;
|
|
29
|
+
razon_social?: string;
|
|
30
|
+
condicion_iva?: string;
|
|
15
31
|
}
|
|
16
32
|
|
|
17
33
|
export interface InvoiceItem {
|
|
18
34
|
descripcion: string;
|
|
19
35
|
precio: number;
|
|
36
|
+
cantidad?: number;
|
|
37
|
+
alicuota_iva?: number;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface Tributo {
|
|
41
|
+
id: number;
|
|
42
|
+
descripcion: string;
|
|
43
|
+
base_imponible: number;
|
|
44
|
+
alicuota: number;
|
|
45
|
+
importe: number;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface Opcional {
|
|
49
|
+
id: string;
|
|
50
|
+
valor: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface CondicionesIvaResponse {
|
|
54
|
+
condiciones: { codigo: number; nombre: string }[];
|
|
20
55
|
}
|
|
21
56
|
|
|
22
57
|
export interface InvoiceInput {
|
|
23
58
|
cuit_emisor: string;
|
|
24
59
|
punto_de_venta: number;
|
|
25
|
-
tipo_comprobante: 'A' | 'B' | 'C' | 'M'
|
|
60
|
+
tipo_comprobante: 'A' | 'B' | 'C' | 'M' | 'E'
|
|
61
|
+
| 'NCA' | 'NCB' | 'NCC' | 'NCE' | 'NCM'
|
|
62
|
+
| 'NDA' | 'NDB' | 'NDC' | 'NDE' | 'NDM'
|
|
63
|
+
| 'FCE_A' | 'FCE_B' | 'FCE_C'
|
|
64
|
+
| 'FCE_NDA' | 'FCE_NDB' | 'FCE_NDC'
|
|
65
|
+
| 'FCE_NCA' | 'FCE_NCB' | 'FCE_NCC';
|
|
26
66
|
receptor: InvoiceReceptor;
|
|
27
67
|
conceptos: InvoiceItem[];
|
|
68
|
+
/**
|
|
69
|
+
* Default `true`: los `conceptos[].precio` se envΓan con IVA incluido (precio final).
|
|
70
|
+
* Con `false`, los precios se interpretan como netos (sin IVA) y KeyCAE calcula
|
|
71
|
+
* y adiciona el IVA segΓΊn la `alicuota_iva` de cada Γtem.
|
|
72
|
+
* Sin efecto en comprobantes sin discriminaciΓ³n de IVA (tipo C / E).
|
|
73
|
+
*/
|
|
74
|
+
iva_incluido?: boolean;
|
|
75
|
+
tributos?: Tributo[];
|
|
76
|
+
moneda?: string;
|
|
77
|
+
moneda_cotizacion?: number;
|
|
78
|
+
fecha_comprobante?: string;
|
|
79
|
+
fecha_servicio_desde?: string;
|
|
80
|
+
fecha_servicio_hasta?: string;
|
|
81
|
+
fecha_vto_pago?: string;
|
|
82
|
+
condicion_iva_receptor?: number;
|
|
83
|
+
opcionales?: Opcional[];
|
|
28
84
|
brand_logo_url?: string;
|
|
29
85
|
brand_color?: string;
|
|
86
|
+
cbtes_asociados?: {
|
|
87
|
+
tipo: string | number;
|
|
88
|
+
punto_de_venta: number;
|
|
89
|
+
numero: number;
|
|
90
|
+
cuit?: string;
|
|
91
|
+
fecha?: string;
|
|
92
|
+
}[];
|
|
30
93
|
}
|
|
31
94
|
|
|
32
95
|
export interface InvoiceResponse {
|
|
@@ -72,7 +135,7 @@ export interface DelegationInput {
|
|
|
72
135
|
|
|
73
136
|
export interface DelegationResponse {
|
|
74
137
|
id: string;
|
|
75
|
-
status: 'pending' | 'accepted' | 'rejected';
|
|
138
|
+
status: 'pending' | 'accepted' | 'rejected' | 'pending_auto';
|
|
76
139
|
cuit: string;
|
|
77
140
|
organization: string;
|
|
78
141
|
representativeCuit: string;
|
|
@@ -104,13 +167,92 @@ export interface KmsImportInput {
|
|
|
104
167
|
private_key: string;
|
|
105
168
|
}
|
|
106
169
|
|
|
170
|
+
export interface PuntoDeVenta {
|
|
171
|
+
numero: number;
|
|
172
|
+
tipoEmision: string;
|
|
173
|
+
tipoAutomatizacion?: string;
|
|
174
|
+
fechaServicioDesde?: string;
|
|
175
|
+
fechaServicioHasta?: string;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export interface EmissionCapability {
|
|
179
|
+
cuit: string;
|
|
180
|
+
condicion_iva: string;
|
|
181
|
+
compatible_types: string[];
|
|
182
|
+
recommendation: string;
|
|
183
|
+
tip: string;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export interface HealthResponse {
|
|
187
|
+
status: string;
|
|
188
|
+
version?: string;
|
|
189
|
+
uptime?: number;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// ββ Partners (ERP / SaaS Integrations) ββββββββββββββββββββββββββββββ
|
|
193
|
+
|
|
194
|
+
export interface PartnerSubaccountInput {
|
|
195
|
+
/** CUIT fiscal del cliente final (11 dΓgitos, sin guiones) */
|
|
196
|
+
cuit: string;
|
|
197
|
+
/** RazΓ³n social del cliente final */
|
|
198
|
+
organization: string;
|
|
199
|
+
/** Email de acceso del cliente final */
|
|
200
|
+
email: string;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export interface PartnerSubaccountResponse {
|
|
204
|
+
id: string;
|
|
205
|
+
cuit: string;
|
|
206
|
+
organization: string;
|
|
207
|
+
email: string;
|
|
208
|
+
/** ContraseΓ±a generada β se devuelve UNA sola vez. Entregar por canal seguro. */
|
|
209
|
+
password: string;
|
|
210
|
+
/** API Key live de la subcuenta β se devuelve UNA sola vez. */
|
|
211
|
+
api_key: string;
|
|
212
|
+
partner_id: string;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
export interface PartnerClient {
|
|
216
|
+
cuit: string;
|
|
217
|
+
organization: string;
|
|
218
|
+
email: string;
|
|
219
|
+
plan: 'free' | 'developer' | 'platform';
|
|
220
|
+
invoices_this_month: number;
|
|
221
|
+
created_at: string | null;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export interface PartnerClientsResponse {
|
|
225
|
+
partner_id: string;
|
|
226
|
+
total: number;
|
|
227
|
+
clients: PartnerClient[];
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export interface PartnerPreauthResponse {
|
|
231
|
+
success: boolean;
|
|
232
|
+
message: string;
|
|
233
|
+
partner_id: string;
|
|
234
|
+
cuit: string;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
export interface PartnerPublicConfig {
|
|
238
|
+
id: string;
|
|
239
|
+
name: string;
|
|
240
|
+
logo_url: string;
|
|
241
|
+
brand_color: string;
|
|
242
|
+
billing_mode: 'decentralized' | 'consolidated';
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
246
|
+
// CLIENT
|
|
247
|
+
// ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
248
|
+
|
|
107
249
|
export class KeyCaeClient {
|
|
108
250
|
private apiKey: string;
|
|
109
251
|
private baseUrl: string;
|
|
110
252
|
|
|
111
|
-
constructor(apiKey: string, baseUrl: string = 'https://
|
|
253
|
+
constructor(apiKey: string, baseUrl: string = 'https://keycae.ar') {
|
|
112
254
|
this.apiKey = apiKey;
|
|
113
|
-
this.baseUrl = baseUrl;
|
|
255
|
+
this.baseUrl = baseUrl.replace(/\/$/, '');
|
|
114
256
|
}
|
|
115
257
|
|
|
116
258
|
private async request<T>(
|
|
@@ -135,16 +277,23 @@ export class KeyCaeClient {
|
|
|
135
277
|
});
|
|
136
278
|
|
|
137
279
|
if (!response.ok) {
|
|
138
|
-
let
|
|
280
|
+
let errorData: any;
|
|
139
281
|
try {
|
|
140
|
-
|
|
141
|
-
} catch
|
|
142
|
-
|
|
282
|
+
errorData = await response.json();
|
|
283
|
+
} catch {
|
|
284
|
+
const text = await response.text().catch(() => '');
|
|
285
|
+
throw new Error(`KeyCAE API Error (${response.status}): ${text || response.statusText}`);
|
|
286
|
+
}
|
|
287
|
+
const message = errorData?.error?.message || JSON.stringify(errorData);
|
|
288
|
+
const hint = errorData?.error?.ai_action_hint || '';
|
|
289
|
+
throw new Error(`KeyCAE API Error (${response.status}): ${message}${hint ? ` [hint: ${hint}]` : ''}`);
|
|
143
290
|
}
|
|
144
291
|
|
|
145
292
|
return response.json() as Promise<T>;
|
|
146
293
|
}
|
|
147
294
|
|
|
295
|
+
// ββ Taxpayers βββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
296
|
+
|
|
148
297
|
/**
|
|
149
298
|
* Consultar Contribuyente en PadrΓ³n ARCA
|
|
150
299
|
*/
|
|
@@ -152,6 +301,40 @@ export class KeyCaeClient {
|
|
|
152
301
|
return this.request<TaxpayerResponse>('GET', `/v1/taxpayers/${cuit}`);
|
|
153
302
|
}
|
|
154
303
|
|
|
304
|
+
/**
|
|
305
|
+
* Verificar quΓ© tipos de factura puede emitir un CUIT segΓΊn su condiciΓ³n fiscal
|
|
306
|
+
*/
|
|
307
|
+
async checkEmissionCapability(cuit: string): Promise<EmissionCapability> {
|
|
308
|
+
const taxpayer = await this.getTaxpayer(cuit);
|
|
309
|
+
const condition = taxpayer.condicion_iva || taxpayer.estado || '';
|
|
310
|
+
let compatibleTypes: string[] = [];
|
|
311
|
+
let recommendation = '';
|
|
312
|
+
|
|
313
|
+
if (condition.toLowerCase().includes('monotributo')) {
|
|
314
|
+
compatibleTypes = ['C', 'M'];
|
|
315
|
+
recommendation = 'Como Monotributista, podΓ©s emitir Factura C (exenta) o Factura M (monotributo). NO podΓ©s emitir Factura A o B.';
|
|
316
|
+
} else if (condition.toLowerCase().includes('responsable inscripto') || condition.toLowerCase().includes('ri')) {
|
|
317
|
+
compatibleTypes = ['A', 'B'];
|
|
318
|
+
recommendation = 'Como Responsable Inscripto, podΓ©s emitir Factura A (IVA discriminado) o Factura B (consumidor final).';
|
|
319
|
+
} else if (condition.toLowerCase().includes('exento')) {
|
|
320
|
+
compatibleTypes = ['C'];
|
|
321
|
+
recommendation = 'Como Exento, solo podΓ©s emitir Factura C (exenta).';
|
|
322
|
+
} else {
|
|
323
|
+
compatibleTypes = ['C'];
|
|
324
|
+
recommendation = 'No se pudo determinar la condiciΓ³n impositiva. Se recomienda Factura C por defecto.';
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
return {
|
|
328
|
+
cuit,
|
|
329
|
+
condicion_iva: condition,
|
|
330
|
+
compatible_types: compatibleTypes,
|
|
331
|
+
recommendation,
|
|
332
|
+
tip: 'UsΓ‘ estos tipos al emitir facturas con emitInvoice para evitar errores de ARCA.'
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// ββ Delegations βββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
337
|
+
|
|
155
338
|
/**
|
|
156
339
|
* Registrar / Iniciar Direct Delegation
|
|
157
340
|
*/
|
|
@@ -166,6 +349,8 @@ export class KeyCaeClient {
|
|
|
166
349
|
return this.request<DelegationResponse>('GET', '/v1/delegations/status');
|
|
167
350
|
}
|
|
168
351
|
|
|
352
|
+
// ββ Credentials (KMS) ββββββββββββββββββββββββββββββββββββββββββββ
|
|
353
|
+
|
|
169
354
|
/**
|
|
170
355
|
* Crear BΓ³veda de Claves KMS & Generar CSR
|
|
171
356
|
*/
|
|
@@ -173,6 +358,13 @@ export class KeyCaeClient {
|
|
|
173
358
|
return this.request<KmsCredentialResponse>('POST', '/v1/credentials', data);
|
|
174
359
|
}
|
|
175
360
|
|
|
361
|
+
/**
|
|
362
|
+
* Listar Credenciales Digitales Registradas
|
|
363
|
+
*/
|
|
364
|
+
async listCredentials(): Promise<KmsCredentialResponse[]> {
|
|
365
|
+
return this.request<KmsCredentialResponse[]>('GET', '/v1/credentials');
|
|
366
|
+
}
|
|
367
|
+
|
|
176
368
|
/**
|
|
177
369
|
* Importar Credenciales de Firma Existentes (.key y .crt)
|
|
178
370
|
*/
|
|
@@ -194,6 +386,8 @@ export class KeyCaeClient {
|
|
|
194
386
|
return this.request<any>('DELETE', `/v1/credentials/${id}`);
|
|
195
387
|
}
|
|
196
388
|
|
|
389
|
+
// ββ Invoices ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
390
|
+
|
|
197
391
|
/**
|
|
198
392
|
* Emitir Factura ElectrΓ³nica Homologada (CAE)
|
|
199
393
|
*/
|
|
@@ -201,11 +395,30 @@ export class KeyCaeClient {
|
|
|
201
395
|
return this.request<InvoiceResponse>('POST', '/v1/invoices', data, idempotencyKey);
|
|
202
396
|
}
|
|
203
397
|
|
|
398
|
+
/**
|
|
399
|
+
* Obtener Detalles de una Factura por ID
|
|
400
|
+
*/
|
|
401
|
+
async getInvoice(id: string): Promise<InvoiceResponse> {
|
|
402
|
+
return this.request<InvoiceResponse>('GET', `/v1/invoices/${id}`);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* Listar Facturas Recientes
|
|
407
|
+
*/
|
|
408
|
+
async listInvoices(limit: number = 10, offset: number = 0): Promise<{ invoices: InvoiceResponse[]; total: number }> {
|
|
409
|
+
const params = new URLSearchParams({ limit: String(limit), offset: String(offset) });
|
|
410
|
+
return this.request<any>('GET', `/v1/invoices?${params}`);
|
|
411
|
+
}
|
|
412
|
+
|
|
204
413
|
/**
|
|
205
414
|
* Descargar PDF de Factura (Retorna el Stream / ArrayBuffer)
|
|
206
415
|
*/
|
|
207
|
-
async getInvoicePdfBuffer(id: string): Promise<Buffer> {
|
|
208
|
-
const
|
|
416
|
+
async getInvoicePdfBuffer(id: string, options?: { format?: 'a4' | 'ticket' }): Promise<Buffer> {
|
|
417
|
+
const url = new URL(`${this.baseUrl}/v1/invoices/${id}/pdf`);
|
|
418
|
+
if (options?.format) {
|
|
419
|
+
url.searchParams.append('format', options.format);
|
|
420
|
+
}
|
|
421
|
+
const response = await fetch(url.toString(), {
|
|
209
422
|
method: 'GET',
|
|
210
423
|
headers: {
|
|
211
424
|
'Authorization': `Bearer ${this.apiKey}`
|
|
@@ -216,10 +429,20 @@ export class KeyCaeClient {
|
|
|
216
429
|
throw new Error(`Failed to fetch PDF (${response.status})`);
|
|
217
430
|
}
|
|
218
431
|
|
|
219
|
-
|
|
220
|
-
return Buffer.from(arrayBuffer);
|
|
432
|
+
return Buffer.from(await response.arrayBuffer());
|
|
221
433
|
}
|
|
222
434
|
|
|
435
|
+
// ββ Puntos de Venta βββββββββββββββββββββββββββββββββββββββββββββββ
|
|
436
|
+
|
|
437
|
+
/**
|
|
438
|
+
* Listar Puntos de Venta Habilitados para FacturaciΓ³n ElectrΓ³nica
|
|
439
|
+
*/
|
|
440
|
+
async listPuntosDeVenta(): Promise<PuntoDeVenta[]> {
|
|
441
|
+
return this.request<PuntoDeVenta[]>('GET', '/v1/pos');
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
// ββ Billing βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
445
|
+
|
|
223
446
|
/**
|
|
224
447
|
* Obtener Consumos y Estado del Plan (Billing)
|
|
225
448
|
*/
|
|
@@ -227,6 +450,8 @@ export class KeyCaeClient {
|
|
|
227
450
|
return this.request<BillingStatusResponse>('GET', '/v1/billing/status');
|
|
228
451
|
}
|
|
229
452
|
|
|
453
|
+
// ββ Telegram Settings βββββββββββββββββββββββββββββββββββββββββββββ
|
|
454
|
+
|
|
230
455
|
/**
|
|
231
456
|
* Obtener Ajustes de Telegram por Tenant
|
|
232
457
|
*/
|
|
@@ -240,4 +465,66 @@ export class KeyCaeClient {
|
|
|
240
465
|
async saveTelegramSettings(data: TelegramSettingsInput): Promise<any> {
|
|
241
466
|
return this.request<any>('POST', '/v1/settings/telegram', data);
|
|
242
467
|
}
|
|
468
|
+
|
|
469
|
+
// ββ Health ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* Health Check de la API
|
|
473
|
+
*/
|
|
474
|
+
async health(): Promise<HealthResponse> {
|
|
475
|
+
return this.request<HealthResponse>('GET', '/health');
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
// ββ CondiciΓ³n IVA Receptor ββββββββββββββββββββββββββββββββββββββ
|
|
479
|
+
|
|
480
|
+
/**
|
|
481
|
+
* Obtener tabla de condiciones IVA del receptor (15 cΓ³digos oficiales ARCA)
|
|
482
|
+
*/
|
|
483
|
+
async getCondicionesIva(): Promise<CondicionesIvaResponse> {
|
|
484
|
+
return this.request<CondicionesIvaResponse>('GET', '/v1/taxpayers/condiciones-iva');
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// ββ CotizaciΓ³n de Moneda ββββββββββββββββββββββββββββββββββββββββ
|
|
488
|
+
|
|
489
|
+
/**
|
|
490
|
+
* Consultar cotizaciΓ³n de una moneda extranjera vs peso (vΓa ARCA)
|
|
491
|
+
*/
|
|
492
|
+
async getCotizacionMoneda(moneda: string): Promise<{ moneda: string; cotizacion: number }> {
|
|
493
|
+
return this.request<any>('GET', `/v1/cotizacion/${moneda}`);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
// ββ Partners (ERP / SaaS) ββββββββββββββββββββββββββββββββββββββββ
|
|
497
|
+
// Estos mΓ©todos requieren instanciar el cliente con tu API Key de
|
|
498
|
+
// Partner (sk_partner_live_...) β solo desde tu backend.
|
|
499
|
+
|
|
500
|
+
/**
|
|
501
|
+
* Crear una subcuenta completa (usuario + perfil + API Key) para un
|
|
502
|
+
* cliente final de tu ERP. La password y api_key se devuelven una sola vez.
|
|
503
|
+
*/
|
|
504
|
+
async createPartnerSubaccount(data: PartnerSubaccountInput): Promise<PartnerSubaccountResponse> {
|
|
505
|
+
return this.request<PartnerSubaccountResponse>('POST', '/v1/partners/subaccounts', data);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
/**
|
|
509
|
+
* Listar los clientes vinculados a tu partner, con plan y consumo mensual.
|
|
510
|
+
*/
|
|
511
|
+
async listPartnerSubaccounts(): Promise<PartnerClientsResponse> {
|
|
512
|
+
return this.request<PartnerClientsResponse>('GET', '/v1/partners/subaccounts');
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
/**
|
|
516
|
+
* Pre-autorizar el CUIT de un cliente para facturaciΓ³n consolidada
|
|
517
|
+
* (el cliente no pasarΓ‘ por la pasarela de pago al registrarse).
|
|
518
|
+
*/
|
|
519
|
+
async preauthorizeCuit(cuit: string): Promise<PartnerPreauthResponse> {
|
|
520
|
+
return this.request<PartnerPreauthResponse>('POST', '/v1/partners/preauthorize', { cuit });
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
/**
|
|
524
|
+
* Consultar la configuraciΓ³n pΓΊblica de co-branding de un partner
|
|
525
|
+
* (endpoint pΓΊblico β no requiere autenticaciΓ³n).
|
|
526
|
+
*/
|
|
527
|
+
async getPartnerConfig(partnerId: string): Promise<PartnerPublicConfig> {
|
|
528
|
+
return this.request<PartnerPublicConfig>('GET', `/v1/partners/${encodeURIComponent(partnerId)}/config`);
|
|
529
|
+
}
|
|
243
530
|
}
|