@vorluno/niiko-sdk 0.1.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 +13 -0
- package/README.md +103 -0
- package/dist/index.d.ts +354 -0
- package/dist/index.js +174 -0
- package/index.ts +428 -0
- package/package.json +48 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Copyright 2026 Vorluno
|
|
2
|
+
|
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
you may not use this file except in compliance with the License.
|
|
5
|
+
You may obtain a copy of the License at
|
|
6
|
+
|
|
7
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
|
|
9
|
+
Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
See the License for the specific language governing permissions and
|
|
13
|
+
limitations under the License.
|
package/README.md
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# @vorluno/niiko-sdk
|
|
2
|
+
|
|
3
|
+
The TypeScript client for the niiko actions API. One typed method per action, three outcomes, zero dependencies.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@vorluno/niiko-sdk) [](https://nodejs.org)   [](https://developers.niiko.org)
|
|
6
|
+
|
|
7
|
+
**A client that knows the actions it was written for is stale the day a new one opens.** This one is
|
|
8
|
+
generated from the niiko action manifest, in the same run as the Python client and the reference (plan `6c3240a7b22d`),
|
|
9
|
+
so an action that opens on the server appears here as a typed method at once — and nothing in this repository
|
|
10
|
+
is edited by hand.
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install @vorluno/niiko-sdk
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Zero runtime dependencies. A client that drags an HTTP library along forces whoever installs it to resolve a
|
|
19
|
+
version conflict just to send a POST.
|
|
20
|
+
|
|
21
|
+
## Use
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import { Niiko } from "@vorluno/niiko-sdk";
|
|
25
|
+
|
|
26
|
+
const niiko = new Niiko({ apiKey: process.env.NIIKO_API_KEY! });
|
|
27
|
+
|
|
28
|
+
// The second argument is the idempotency key: keep it if you retry.
|
|
29
|
+
const r = await niiko.createLead({
|
|
30
|
+
submissionId: "01890a5d-ac96-774b-bcce-b302099a8057",
|
|
31
|
+
source: "web_form",
|
|
32
|
+
}, crypto.randomUUID());
|
|
33
|
+
|
|
34
|
+
if (r.status === "done") console.log(r.output);
|
|
35
|
+
else if (r.status === "refused") console.error(r.reason, r.detail?.message);
|
|
36
|
+
else console.log("waiting for a human signature", r.proposalId);
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Three outcomes, not two
|
|
40
|
+
|
|
41
|
+
| `status` | Meaning |
|
|
42
|
+
|---|---|
|
|
43
|
+
| `done` | Done. Carries the `output`. |
|
|
44
|
+
| `pending_approval` | **Waits for a human signature** and may complete hours later. A webhook tells you when it resolves. |
|
|
45
|
+
| `refused` | Not done, and `reason` says why. `detail.message`, when present, says what to do. |
|
|
46
|
+
|
|
47
|
+
A two-outcome contract forces the third one to disguise itself as another, and the disguised one is always
|
|
48
|
+
the one that takes longest to understand. Branch once on `status`; a refusal is a state, not an exception.
|
|
49
|
+
|
|
50
|
+
> [!NOTE]
|
|
51
|
+
> Send an idempotency key with every request. A timeout retry with the same key **does not execute again**: it
|
|
52
|
+
> answers `refused` with `reason: "duplicate"` and what happened the first time. Without one, a retry is a new
|
|
53
|
+
> request. The protection lasts 24 hours.
|
|
54
|
+
|
|
55
|
+
> [!IMPORTANT]
|
|
56
|
+
> Each action needs **two** permissions: a key with that action's scope, **and** the workspace owner having
|
|
57
|
+
> switched it on (Administration → Permissions). Holding the key is not enough — they are two decisions made
|
|
58
|
+
> by different people.
|
|
59
|
+
|
|
60
|
+
## The actions today (13)
|
|
61
|
+
|
|
62
|
+
| Action | Method | What it does |
|
|
63
|
+
|---|---|---|
|
|
64
|
+
| `miira.lead_create` | `createLead` | Creates a new lead in the workspace CRM from its contact details. If a matching one already exists it is not duplicated: the reply is `ambiguous` with the candidates. |
|
|
65
|
+
| `crm.call_logged` | `loggedCall` | Logs what was discussed in a call on a client's record, naming the client; optionally creates the follow-up with its date. Reads nothing and calls no one. |
|
|
66
|
+
| `crm.owner_assigned` | `assignedOwner` | Changes who owns a client, naming the client and the team member (by name or email). If either is ambiguous it refuses with the list. |
|
|
67
|
+
| `crm.stage_moved` | `movedStage` | Moves a client's open deal to another pipeline stage, naming the client and the stage. Creates no deals: with no open deal it refuses, and with several it refuses with the list. |
|
|
68
|
+
| `kiipu.invoice_proposed` | `proposedInvoice` | Prepares an invoice as a DRAFT for a client named by name, with its lines and taxes. Does NOT issue it, does NOT number it and does NOT count as debt: a person reviews and issues it in Kiipu. Does not create the client if it does not exist. |
|
|
69
|
+
| `crm.task_created` | `createdTask` | Creates a reminder (a task with date and time) on a client named by name. Does not log a call: that is crm.call_logged. Does not create the client if it does not exist. |
|
|
70
|
+
| `crm.deal_created` | `createdDeal` | Opens a new deal in the pipeline for a client named by name, with a title, an optional value in USD, an optional stage (by name; without it, the first one) and an optional owner. Does not check for other open deals: it returns how many remain so a duplicate is visible. Does not win or lose it: that is crm.stage_moved. |
|
|
71
|
+
| `crm.note_added` | `addedNote` | Saves a note on a client's record, naming the client: something to know next time, with no call and no date. For a call use crm.call_logged; for a dated reminder, crm.task_created. |
|
|
72
|
+
| `crm.contact_added` | `addedContact` | Adds a person (name, and optionally email, phone and role) to a client's record, naming the client. Does not make them the primary contact and does not create the client. If someone with that email or phone already existed, the reply says so but does not block it. |
|
|
73
|
+
| `miira.broadcast_quoted` | `quotedBroadcast` | Quotes sending the SAME WhatsApp message to several clients named by name (up to 50). Sends NOTHING: per client, it says whether the text goes as-is (24-hour window open, free), whether an approved template is needed and what it costs, or why that client cannot be messaged. Returns a signed quote valid for 15 minutes; to send, call miira.broadcast_sent with it. Show the quote to the person first. |
|
|
74
|
+
| `miira.broadcast_sent` | `sentBroadcast` | Sends the WhatsApp broadcast quoted by miira.broadcast_quoted, exactly to whom and how the quote said. If anything changed (window, consent, rate) it refuses with a new quote to confirm again. Costs money when templates are involved: do not call it without the person having seen the cost. |
|
|
75
|
+
| `kiipu.draft_voided` | `voidedDraft` | Voids a DRAFT invoice (one created with kiipu.invoice_proposed and not yet issued), by its id or by the client's name when it is their only draft. Does not void issued invoices: that is for a person in Kiipu. |
|
|
76
|
+
| `kiipu.payment_reported` | `reportedPayment` | Leaves in the Kiipu approval queue the notice that a client (by name) paid a given amount of an open invoice. Does NOT apply the payment and touches no balances: a person checks it against the bank and applies it. If the client has several open invoices the number must be given. |
|
|
77
|
+
|
|
78
|
+
## What this client does not do
|
|
79
|
+
|
|
80
|
+
| Not included | Why |
|
|
81
|
+
|---|---|
|
|
82
|
+
| **Validate your input** | It could — the schema is published — and that would be worse: a client that validates can disagree with the server, and the likely direction of the error is the dangerous one (approving what the server will reject). The server validates, and its refusal travels with a name. What this client gives you is the **shape**, in your editor, before sending anything. |
|
|
83
|
+
| **Read anything** | This API exposes verbs, not rows. There is nothing to list or paginate. |
|
|
84
|
+
| **Retry on its own** | A retry is a decision about your idempotency key. The client keeps it explicit. |
|
|
85
|
+
|
|
86
|
+
## Support
|
|
87
|
+
|
|
88
|
+
| | |
|
|
89
|
+
|---|---|
|
|
90
|
+
| **Versioning** | Semantic. Every visible change is in the [changelog](https://developers.niiko.org/#changelog) of the API reference. |
|
|
91
|
+
| **Regeneration** | This repository is generated from the niiko action manifest. When an action opens or a contract changes, a new version is published — nothing here is edited by hand. |
|
|
92
|
+
| **Issues** | [vorluno/niiko-sdk-typescript/issues](https://github.com/vorluno/niiko-sdk-typescript/issues) — a fault of the API itself starts at [developers.niiko.org](https://developers.niiko.org). |
|
|
93
|
+
| **Security** | `security@vorluno.dev` — first response within 48 hours, patch or plan within 7 days. |
|
|
94
|
+
|
|
95
|
+
## Related
|
|
96
|
+
|
|
97
|
+
- **[niiko (Python)](https://github.com/vorluno/niiko-sdk-python)** — the Python client, same plan.
|
|
98
|
+
- **[niiko-cli](https://github.com/vorluno/niiko-cli)** — the same actions from the terminal, with the outcome in the exit code.
|
|
99
|
+
- **[n8n-nodes-niiko](https://github.com/vorluno/n8n-nodes-niiko)** — the same actions as an n8n node.
|
|
100
|
+
- **[niiko-mcp-server](https://github.com/vorluno/niiko-mcp-server)** — the same actions as MCP tools, for Claude and other AI clients.
|
|
101
|
+
- **[developers.niiko.org](https://developers.niiko.org)** — the API reference this is generated alongside.
|
|
102
|
+
|
|
103
|
+
<sub>Built and maintained by <a href="https://vorluno.dev">Vorluno</a>, a software studio in Panama, and generated from <a href="https://niiko.org">niiko</a>'s production action manifest — the same one the server enforces. Apache 2.0.</sub>
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
/** The three outcomes. Branch once on `status` and you know where you are. */
|
|
2
|
+
export type Result<T> = {
|
|
3
|
+
status: "done";
|
|
4
|
+
output: T;
|
|
5
|
+
idempotencyKey: string;
|
|
6
|
+
}
|
|
7
|
+
/** Waits for a human signature and may complete hours later. You get notified by webhook. */
|
|
8
|
+
| {
|
|
9
|
+
status: "pending_approval";
|
|
10
|
+
proposalId: string | null;
|
|
11
|
+
autonomy: string;
|
|
12
|
+
}
|
|
13
|
+
/** Not done. `reason` is a named reason and `detail.message`, when present, says what to do. */
|
|
14
|
+
| {
|
|
15
|
+
status: "refused";
|
|
16
|
+
reason: string;
|
|
17
|
+
detail?: Record<string, unknown>;
|
|
18
|
+
};
|
|
19
|
+
export declare class NiikoError extends Error {
|
|
20
|
+
readonly status: number;
|
|
21
|
+
readonly body: unknown;
|
|
22
|
+
constructor(status: number, body: unknown);
|
|
23
|
+
}
|
|
24
|
+
export interface CreateLeadInput {
|
|
25
|
+
submissionId: string;
|
|
26
|
+
source: "web_form" | "referral" | "api" | "import" | "event" | "other";
|
|
27
|
+
name?: string;
|
|
28
|
+
email?: string;
|
|
29
|
+
phone?: string;
|
|
30
|
+
fields?: Record<string, unknown>;
|
|
31
|
+
consent?: {
|
|
32
|
+
email: boolean;
|
|
33
|
+
whatsapp: boolean;
|
|
34
|
+
source: "api" | "web_form" | "verbal" | "llamada" | "visita" | "imported";
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export interface CreateLeadOutput {
|
|
38
|
+
outcome: "created" | "existing" | "ambiguous" | "rejected";
|
|
39
|
+
clientId: string | null;
|
|
40
|
+
reason: "honeypot" | "invalid_email" | "disposable_email" | "invalid_identity" | null;
|
|
41
|
+
}
|
|
42
|
+
/** The reasons `miira.lead_create` declares. One outside this list is a server fault, not a state. */
|
|
43
|
+
export type CreateLeadReason = "honeypot" | "invalid_email" | "disposable_email" | "invalid_identity";
|
|
44
|
+
export interface LoggedCallInput {
|
|
45
|
+
client: string;
|
|
46
|
+
summary: string;
|
|
47
|
+
followUp?: {
|
|
48
|
+
what: string;
|
|
49
|
+
dueAt: string;
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
export interface LoggedCallOutput {
|
|
53
|
+
clientId: string;
|
|
54
|
+
clientName: string;
|
|
55
|
+
activityId: string;
|
|
56
|
+
followUpId: string | null;
|
|
57
|
+
}
|
|
58
|
+
/** The reasons `crm.call_logged` declares. One outside this list is a server fault, not a state. */
|
|
59
|
+
export type LoggedCallReason = "cliente_no_encontrado" | "cliente_ambiguo" | "demasiados_clientes" | "sin_permiso";
|
|
60
|
+
export interface AssignedOwnerInput {
|
|
61
|
+
client: string;
|
|
62
|
+
owner: string;
|
|
63
|
+
}
|
|
64
|
+
export interface AssignedOwnerOutput {
|
|
65
|
+
clientId: string;
|
|
66
|
+
clientName: string;
|
|
67
|
+
ownerUserId: string;
|
|
68
|
+
ownerName: string;
|
|
69
|
+
}
|
|
70
|
+
/** The reasons `crm.owner_assigned` declares. One outside this list is a server fault, not a state. */
|
|
71
|
+
export type AssignedOwnerReason = "cliente_no_encontrado" | "cliente_ambiguo" | "demasiados_clientes" | "persona_no_encontrada" | "persona_ambigua" | "sin_permiso";
|
|
72
|
+
export interface MovedStageInput {
|
|
73
|
+
client: string;
|
|
74
|
+
stage: string;
|
|
75
|
+
lostReason?: string;
|
|
76
|
+
}
|
|
77
|
+
export interface MovedStageOutput {
|
|
78
|
+
dealId: string;
|
|
79
|
+
clientId: string;
|
|
80
|
+
clientName: string;
|
|
81
|
+
stageName: string;
|
|
82
|
+
won: boolean;
|
|
83
|
+
firstWon: boolean;
|
|
84
|
+
}
|
|
85
|
+
/** The reasons `crm.stage_moved` declares. One outside this list is a server fault, not a state. */
|
|
86
|
+
export type MovedStageReason = "cliente_no_encontrado" | "cliente_ambiguo" | "demasiados_clientes" | "sin_negocio_abierto" | "varios_negocios" | "etapa_no_encontrada" | "negocio_cerrado" | "ya_en_esa_etapa" | "sin_permiso";
|
|
87
|
+
export interface ProposedInvoiceInput {
|
|
88
|
+
client: string;
|
|
89
|
+
lines: {
|
|
90
|
+
concept: string;
|
|
91
|
+
quantity: string;
|
|
92
|
+
unitPriceUsd: string;
|
|
93
|
+
tax: "exempt" | "itbms_7" | "itbms_10" | "itbms_15";
|
|
94
|
+
}[];
|
|
95
|
+
dueAt?: string;
|
|
96
|
+
series?: string;
|
|
97
|
+
}
|
|
98
|
+
export interface ProposedInvoiceOutput {
|
|
99
|
+
invoiceId: string;
|
|
100
|
+
clientId: string;
|
|
101
|
+
clientName: string;
|
|
102
|
+
status: "draft";
|
|
103
|
+
subtotalUsd: string;
|
|
104
|
+
taxUsd: string;
|
|
105
|
+
totalUsd: string;
|
|
106
|
+
dueAt: string;
|
|
107
|
+
series: string;
|
|
108
|
+
issueAt: "/kiipu/facturas";
|
|
109
|
+
}
|
|
110
|
+
/** The reasons `kiipu.invoice_proposed` declares. One outside this list is a server fault, not a state. */
|
|
111
|
+
export type ProposedInvoiceReason = "cliente_no_encontrado" | "cliente_ambiguo" | "demasiados_clientes" | "sin_permiso";
|
|
112
|
+
export interface CreatedTaskInput {
|
|
113
|
+
client: string;
|
|
114
|
+
what: string;
|
|
115
|
+
dueAt: string;
|
|
116
|
+
}
|
|
117
|
+
export interface CreatedTaskOutput {
|
|
118
|
+
clientId: string;
|
|
119
|
+
clientName: string;
|
|
120
|
+
taskId: string;
|
|
121
|
+
dueAt: string;
|
|
122
|
+
}
|
|
123
|
+
/** The reasons `crm.task_created` declares. One outside this list is a server fault, not a state. */
|
|
124
|
+
export type CreatedTaskReason = "cliente_no_encontrado" | "cliente_ambiguo" | "demasiados_clientes" | "sin_permiso";
|
|
125
|
+
export interface CreatedDealInput {
|
|
126
|
+
client: string;
|
|
127
|
+
title: string;
|
|
128
|
+
valueUsd?: string;
|
|
129
|
+
stage?: string;
|
|
130
|
+
owner?: string;
|
|
131
|
+
}
|
|
132
|
+
export interface CreatedDealOutput {
|
|
133
|
+
dealId: string;
|
|
134
|
+
clientId: string;
|
|
135
|
+
clientName: string;
|
|
136
|
+
title: string;
|
|
137
|
+
valueUsd: string | null;
|
|
138
|
+
stageName: string;
|
|
139
|
+
ownerName: string | null;
|
|
140
|
+
openDeals: number;
|
|
141
|
+
}
|
|
142
|
+
/** The reasons `crm.deal_created` declares. One outside this list is a server fault, not a state. */
|
|
143
|
+
export type CreatedDealReason = "cliente_no_encontrado" | "cliente_ambiguo" | "demasiados_clientes" | "etapa_no_encontrada" | "etapa_cerrada" | "persona_no_encontrada" | "persona_ambigua" | "sin_permiso";
|
|
144
|
+
export interface AddedNoteInput {
|
|
145
|
+
client: string;
|
|
146
|
+
note: string;
|
|
147
|
+
}
|
|
148
|
+
export interface AddedNoteOutput {
|
|
149
|
+
clientId: string;
|
|
150
|
+
clientName: string;
|
|
151
|
+
noteId: string;
|
|
152
|
+
}
|
|
153
|
+
/** The reasons `crm.note_added` declares. One outside this list is a server fault, not a state. */
|
|
154
|
+
export type AddedNoteReason = "cliente_no_encontrado" | "cliente_ambiguo" | "demasiados_clientes" | "sin_permiso";
|
|
155
|
+
export interface AddedContactInput {
|
|
156
|
+
client: string;
|
|
157
|
+
name: string;
|
|
158
|
+
email?: string;
|
|
159
|
+
phone?: string;
|
|
160
|
+
role?: string;
|
|
161
|
+
}
|
|
162
|
+
export interface AddedContactOutput {
|
|
163
|
+
clientId: string;
|
|
164
|
+
clientName: string;
|
|
165
|
+
contactId: string;
|
|
166
|
+
possibleDuplicate: boolean;
|
|
167
|
+
}
|
|
168
|
+
/** The reasons `crm.contact_added` declares. One outside this list is a server fault, not a state. */
|
|
169
|
+
export type AddedContactReason = "cliente_no_encontrado" | "cliente_ambiguo" | "demasiados_clientes" | "sin_permiso";
|
|
170
|
+
export interface QuotedBroadcastInput {
|
|
171
|
+
clients: string[];
|
|
172
|
+
message: string;
|
|
173
|
+
template?: string;
|
|
174
|
+
templateValues?: string[];
|
|
175
|
+
}
|
|
176
|
+
export interface QuotedBroadcastOutput {
|
|
177
|
+
rows: {
|
|
178
|
+
client: string;
|
|
179
|
+
clientId: string | null;
|
|
180
|
+
clientName: string | null;
|
|
181
|
+
outcome: "free_text" | "template" | "needs_template" | "no_phone" | "suppressed" | "consent_revoked" | "no_marketing_consent" | "quiet_hours" | "not_found" | "ambiguous" | "too_many";
|
|
182
|
+
costUsd: string | null;
|
|
183
|
+
candidates: string[];
|
|
184
|
+
}[];
|
|
185
|
+
totals: {
|
|
186
|
+
freeText: number;
|
|
187
|
+
template: number;
|
|
188
|
+
skipped: number;
|
|
189
|
+
costUsd: string;
|
|
190
|
+
};
|
|
191
|
+
quote: string | null;
|
|
192
|
+
expiresAt: string | null;
|
|
193
|
+
}
|
|
194
|
+
/** The reasons `miira.broadcast_quoted` declares. One outside this list is a server fault, not a state. */
|
|
195
|
+
export type QuotedBroadcastReason = "plantilla_invalida" | "tarifas_vencidas" | "sin_permiso";
|
|
196
|
+
export interface SentBroadcastInput {
|
|
197
|
+
quote: string;
|
|
198
|
+
}
|
|
199
|
+
export interface SentBroadcastOutput {
|
|
200
|
+
queued: {
|
|
201
|
+
clientId: string;
|
|
202
|
+
clientName: string;
|
|
203
|
+
mode: "free_text" | "template";
|
|
204
|
+
outboxId: string;
|
|
205
|
+
}[];
|
|
206
|
+
costUsd: string;
|
|
207
|
+
}
|
|
208
|
+
/** The reasons `miira.broadcast_sent` declares. One outside this list is a server fault, not a state. */
|
|
209
|
+
export type SentBroadcastReason = "presupuesto_invalido" | "presupuesto_vencido" | "presupuesto_cambiado" | "plantilla_invalida" | "tarifas_vencidas" | "sin_permiso";
|
|
210
|
+
export interface VoidedDraftInput {
|
|
211
|
+
invoiceId?: string;
|
|
212
|
+
client?: string;
|
|
213
|
+
}
|
|
214
|
+
export interface VoidedDraftOutput {
|
|
215
|
+
invoiceId: string;
|
|
216
|
+
clientId: string;
|
|
217
|
+
clientName: string;
|
|
218
|
+
totalUsd: string;
|
|
219
|
+
status: "void";
|
|
220
|
+
}
|
|
221
|
+
/** The reasons `kiipu.draft_voided` declares. One outside this list is a server fault, not a state. */
|
|
222
|
+
export type VoidedDraftReason = "cliente_no_encontrado" | "cliente_ambiguo" | "demasiados_clientes" | "borrador_no_encontrado" | "varios_borradores" | "no_es_borrador" | "sin_permiso";
|
|
223
|
+
export interface ReportedPaymentInput {
|
|
224
|
+
client: string;
|
|
225
|
+
amountUsd: string;
|
|
226
|
+
invoice?: string;
|
|
227
|
+
}
|
|
228
|
+
export interface ReportedPaymentOutput {
|
|
229
|
+
submissionId: string;
|
|
230
|
+
clientId: string;
|
|
231
|
+
clientName: string;
|
|
232
|
+
invoiceId: string;
|
|
233
|
+
invoiceNumber: string;
|
|
234
|
+
outstandingUsd: string;
|
|
235
|
+
declaredUsd: string;
|
|
236
|
+
status: "received";
|
|
237
|
+
reviewAt: "/kiipu/aprobaciones";
|
|
238
|
+
}
|
|
239
|
+
/** The reasons `kiipu.payment_reported` declares. One outside this list is a server fault, not a state. */
|
|
240
|
+
export type ReportedPaymentReason = "cliente_no_encontrado" | "cliente_ambiguo" | "demasiados_clientes" | "sin_factura_abierta" | "varias_facturas" | "factura_no_encontrada" | "sin_permiso";
|
|
241
|
+
export interface NiikoOptions {
|
|
242
|
+
/** The workspace API key. Shown ONCE, when created in Settings. */
|
|
243
|
+
apiKey: string;
|
|
244
|
+
baseUrl?: string;
|
|
245
|
+
fetch?: typeof fetch;
|
|
246
|
+
}
|
|
247
|
+
export declare class Niiko {
|
|
248
|
+
#private;
|
|
249
|
+
constructor(o: NiikoOptions);
|
|
250
|
+
/**
|
|
251
|
+
* Creates a new lead in the workspace CRM from its contact details. If a matching one already exists it is not duplicated: the reply is `ambiguous` with the candidates.
|
|
252
|
+
*
|
|
253
|
+
* `miira.lead_create` v1 — scope `miira.lead_create@1`.
|
|
254
|
+
*
|
|
255
|
+
* Needs **two** permissions: a key with that scope, and the workspace having switched the action on.
|
|
256
|
+
*/
|
|
257
|
+
createLead(input: CreateLeadInput, idempotencyKey?: string): Promise<Result<CreateLeadOutput>>;
|
|
258
|
+
/**
|
|
259
|
+
* Logs what was discussed in a call on a client's record, naming the client; optionally creates the follow-up with its date. Reads nothing and calls no one.
|
|
260
|
+
*
|
|
261
|
+
* `crm.call_logged` v1 — scope `crm.call_logged@1`.
|
|
262
|
+
*
|
|
263
|
+
* Needs **two** permissions: a key with that scope, and the workspace having switched the action on.
|
|
264
|
+
*/
|
|
265
|
+
loggedCall(input: LoggedCallInput, idempotencyKey?: string): Promise<Result<LoggedCallOutput>>;
|
|
266
|
+
/**
|
|
267
|
+
* Changes who owns a client, naming the client and the team member (by name or email). If either is ambiguous it refuses with the list.
|
|
268
|
+
*
|
|
269
|
+
* `crm.owner_assigned` v1 — scope `crm.owner_assigned@1`.
|
|
270
|
+
*
|
|
271
|
+
* Needs **two** permissions: a key with that scope, and the workspace having switched the action on.
|
|
272
|
+
*/
|
|
273
|
+
assignedOwner(input: AssignedOwnerInput, idempotencyKey?: string): Promise<Result<AssignedOwnerOutput>>;
|
|
274
|
+
/**
|
|
275
|
+
* Moves a client's open deal to another pipeline stage, naming the client and the stage. Creates no deals: with no open deal it refuses, and with several it refuses with the list.
|
|
276
|
+
*
|
|
277
|
+
* `crm.stage_moved` v1 — scope `crm.stage_moved@1`.
|
|
278
|
+
*
|
|
279
|
+
* Needs **two** permissions: a key with that scope, and the workspace having switched the action on.
|
|
280
|
+
*/
|
|
281
|
+
movedStage(input: MovedStageInput, idempotencyKey?: string): Promise<Result<MovedStageOutput>>;
|
|
282
|
+
/**
|
|
283
|
+
* Prepares an invoice as a DRAFT for a client named by name, with its lines and taxes. Does NOT issue it, does NOT number it and does NOT count as debt: a person reviews and issues it in Kiipu. Does not create the client if it does not exist.
|
|
284
|
+
*
|
|
285
|
+
* `kiipu.invoice_proposed` v1 — scope `kiipu.invoice_proposed@1`.
|
|
286
|
+
*
|
|
287
|
+
* Needs **two** permissions: a key with that scope, and the workspace having switched the action on.
|
|
288
|
+
*/
|
|
289
|
+
proposedInvoice(input: ProposedInvoiceInput, idempotencyKey?: string): Promise<Result<ProposedInvoiceOutput>>;
|
|
290
|
+
/**
|
|
291
|
+
* Creates a reminder (a task with date and time) on a client named by name. Does not log a call: that is crm.call_logged. Does not create the client if it does not exist.
|
|
292
|
+
*
|
|
293
|
+
* `crm.task_created` v1 — scope `crm.task_created@1`.
|
|
294
|
+
*
|
|
295
|
+
* Needs **two** permissions: a key with that scope, and the workspace having switched the action on.
|
|
296
|
+
*/
|
|
297
|
+
createdTask(input: CreatedTaskInput, idempotencyKey?: string): Promise<Result<CreatedTaskOutput>>;
|
|
298
|
+
/**
|
|
299
|
+
* Opens a new deal in the pipeline for a client named by name, with a title, an optional value in USD, an optional stage (by name; without it, the first one) and an optional owner. Does not check for other open deals: it returns how many remain so a duplicate is visible. Does not win or lose it: that is crm.stage_moved.
|
|
300
|
+
*
|
|
301
|
+
* `crm.deal_created` v1 — scope `crm.deal_created@1`.
|
|
302
|
+
*
|
|
303
|
+
* Needs **two** permissions: a key with that scope, and the workspace having switched the action on.
|
|
304
|
+
*/
|
|
305
|
+
createdDeal(input: CreatedDealInput, idempotencyKey?: string): Promise<Result<CreatedDealOutput>>;
|
|
306
|
+
/**
|
|
307
|
+
* Saves a note on a client's record, naming the client: something to know next time, with no call and no date. For a call use crm.call_logged; for a dated reminder, crm.task_created.
|
|
308
|
+
*
|
|
309
|
+
* `crm.note_added` v1 — scope `crm.note_added@1`.
|
|
310
|
+
*
|
|
311
|
+
* Needs **two** permissions: a key with that scope, and the workspace having switched the action on.
|
|
312
|
+
*/
|
|
313
|
+
addedNote(input: AddedNoteInput, idempotencyKey?: string): Promise<Result<AddedNoteOutput>>;
|
|
314
|
+
/**
|
|
315
|
+
* Adds a person (name, and optionally email, phone and role) to a client's record, naming the client. Does not make them the primary contact and does not create the client. If someone with that email or phone already existed, the reply says so but does not block it.
|
|
316
|
+
*
|
|
317
|
+
* `crm.contact_added` v1 — scope `crm.contact_added@1`.
|
|
318
|
+
*
|
|
319
|
+
* Needs **two** permissions: a key with that scope, and the workspace having switched the action on.
|
|
320
|
+
*/
|
|
321
|
+
addedContact(input: AddedContactInput, idempotencyKey?: string): Promise<Result<AddedContactOutput>>;
|
|
322
|
+
/**
|
|
323
|
+
* Quotes sending the SAME WhatsApp message to several clients named by name (up to 50). Sends NOTHING: per client, it says whether the text goes as-is (24-hour window open, free), whether an approved template is needed and what it costs, or why that client cannot be messaged. Returns a signed quote valid for 15 minutes; to send, call miira.broadcast_sent with it. Show the quote to the person first.
|
|
324
|
+
*
|
|
325
|
+
* `miira.broadcast_quoted` v1 — scope `miira.broadcast_quoted@1`.
|
|
326
|
+
*
|
|
327
|
+
* Needs **two** permissions: a key with that scope, and the workspace having switched the action on.
|
|
328
|
+
*/
|
|
329
|
+
quotedBroadcast(input: QuotedBroadcastInput, idempotencyKey?: string): Promise<Result<QuotedBroadcastOutput>>;
|
|
330
|
+
/**
|
|
331
|
+
* Sends the WhatsApp broadcast quoted by miira.broadcast_quoted, exactly to whom and how the quote said. If anything changed (window, consent, rate) it refuses with a new quote to confirm again. Costs money when templates are involved: do not call it without the person having seen the cost.
|
|
332
|
+
*
|
|
333
|
+
* `miira.broadcast_sent` v1 — scope `miira.broadcast_sent@1`.
|
|
334
|
+
*
|
|
335
|
+
* Needs **two** permissions: a key with that scope, and the workspace having switched the action on.
|
|
336
|
+
*/
|
|
337
|
+
sentBroadcast(input: SentBroadcastInput, idempotencyKey?: string): Promise<Result<SentBroadcastOutput>>;
|
|
338
|
+
/**
|
|
339
|
+
* Voids a DRAFT invoice (one created with kiipu.invoice_proposed and not yet issued), by its id or by the client's name when it is their only draft. Does not void issued invoices: that is for a person in Kiipu.
|
|
340
|
+
*
|
|
341
|
+
* `kiipu.draft_voided` v1 — scope `kiipu.draft_voided@1`.
|
|
342
|
+
*
|
|
343
|
+
* Needs **two** permissions: a key with that scope, and the workspace having switched the action on.
|
|
344
|
+
*/
|
|
345
|
+
voidedDraft(input: VoidedDraftInput, idempotencyKey?: string): Promise<Result<VoidedDraftOutput>>;
|
|
346
|
+
/**
|
|
347
|
+
* Leaves in the Kiipu approval queue the notice that a client (by name) paid a given amount of an open invoice. Does NOT apply the payment and touches no balances: a person checks it against the bank and applies it. If the client has several open invoices the number must be given.
|
|
348
|
+
*
|
|
349
|
+
* `kiipu.payment_reported` v1 — scope `kiipu.payment_reported@1`.
|
|
350
|
+
*
|
|
351
|
+
* Needs **two** permissions: a key with that scope, and the workspace having switched the action on.
|
|
352
|
+
*/
|
|
353
|
+
reportedPayment(input: ReportedPaymentInput, idempotencyKey?: string): Promise<Result<ReportedPaymentOutput>>;
|
|
354
|
+
}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
// GENERATED from the niiko action manifest — plan `6c3240a7b22d`. Do not edit by hand.
|
|
2
|
+
//
|
|
3
|
+
// Every method here exists because an action is DECLARED public. If the server answers `not_exposed`,
|
|
4
|
+
// this copy of the SDK is newer than the deployment — not that you got the name wrong.
|
|
5
|
+
export class NiikoError extends Error {
|
|
6
|
+
status;
|
|
7
|
+
body;
|
|
8
|
+
constructor(status, body) {
|
|
9
|
+
super(`niiko: the server answered ${status}`);
|
|
10
|
+
this.status = status;
|
|
11
|
+
this.body = body;
|
|
12
|
+
this.name = "NiikoError";
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export class Niiko {
|
|
16
|
+
#apiKey;
|
|
17
|
+
#baseUrl;
|
|
18
|
+
#fetch;
|
|
19
|
+
constructor(o) {
|
|
20
|
+
if (!o.apiKey)
|
|
21
|
+
throw new Error("niiko: apiKey is required");
|
|
22
|
+
this.#apiKey = o.apiKey;
|
|
23
|
+
this.#baseUrl = (o.baseUrl ?? "https://niiko.org").replace(/\/+$/, "");
|
|
24
|
+
this.#fetch = o.fetch ?? fetch;
|
|
25
|
+
}
|
|
26
|
+
async #exercise(action, body, idempotencyKey) {
|
|
27
|
+
const r = await this.#fetch(`${this.#baseUrl}/api/v1/actions/${action}`, {
|
|
28
|
+
method: "POST",
|
|
29
|
+
headers: {
|
|
30
|
+
authorization: `Bearer ${this.#apiKey}`,
|
|
31
|
+
"content-type": "application/json",
|
|
32
|
+
// Send it WHENEVER you can: a timeout retry with the same key does not execute again.
|
|
33
|
+
...(idempotencyKey ? { "idempotency-key": idempotencyKey } : {}),
|
|
34
|
+
},
|
|
35
|
+
body: JSON.stringify(body),
|
|
36
|
+
});
|
|
37
|
+
const json = await r.json().catch(() => null);
|
|
38
|
+
// A refusal is NOT an exception: it is a product state, and the caller must be able to branch on it.
|
|
39
|
+
// What does throw is what cannot be read — there is no decision to make there.
|
|
40
|
+
if (json && typeof json === "object" && "status" in json)
|
|
41
|
+
return json;
|
|
42
|
+
throw new NiikoError(r.status, json);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Creates a new lead in the workspace CRM from its contact details. If a matching one already exists it is not duplicated: the reply is `ambiguous` with the candidates.
|
|
46
|
+
*
|
|
47
|
+
* `miira.lead_create` v1 — scope `miira.lead_create@1`.
|
|
48
|
+
*
|
|
49
|
+
* Needs **two** permissions: a key with that scope, and the workspace having switched the action on.
|
|
50
|
+
*/
|
|
51
|
+
async createLead(input, idempotencyKey) {
|
|
52
|
+
return this.#exercise("miira.lead_create", input, idempotencyKey);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Logs what was discussed in a call on a client's record, naming the client; optionally creates the follow-up with its date. Reads nothing and calls no one.
|
|
56
|
+
*
|
|
57
|
+
* `crm.call_logged` v1 — scope `crm.call_logged@1`.
|
|
58
|
+
*
|
|
59
|
+
* Needs **two** permissions: a key with that scope, and the workspace having switched the action on.
|
|
60
|
+
*/
|
|
61
|
+
async loggedCall(input, idempotencyKey) {
|
|
62
|
+
return this.#exercise("crm.call_logged", input, idempotencyKey);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Changes who owns a client, naming the client and the team member (by name or email). If either is ambiguous it refuses with the list.
|
|
66
|
+
*
|
|
67
|
+
* `crm.owner_assigned` v1 — scope `crm.owner_assigned@1`.
|
|
68
|
+
*
|
|
69
|
+
* Needs **two** permissions: a key with that scope, and the workspace having switched the action on.
|
|
70
|
+
*/
|
|
71
|
+
async assignedOwner(input, idempotencyKey) {
|
|
72
|
+
return this.#exercise("crm.owner_assigned", input, idempotencyKey);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Moves a client's open deal to another pipeline stage, naming the client and the stage. Creates no deals: with no open deal it refuses, and with several it refuses with the list.
|
|
76
|
+
*
|
|
77
|
+
* `crm.stage_moved` v1 — scope `crm.stage_moved@1`.
|
|
78
|
+
*
|
|
79
|
+
* Needs **two** permissions: a key with that scope, and the workspace having switched the action on.
|
|
80
|
+
*/
|
|
81
|
+
async movedStage(input, idempotencyKey) {
|
|
82
|
+
return this.#exercise("crm.stage_moved", input, idempotencyKey);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Prepares an invoice as a DRAFT for a client named by name, with its lines and taxes. Does NOT issue it, does NOT number it and does NOT count as debt: a person reviews and issues it in Kiipu. Does not create the client if it does not exist.
|
|
86
|
+
*
|
|
87
|
+
* `kiipu.invoice_proposed` v1 — scope `kiipu.invoice_proposed@1`.
|
|
88
|
+
*
|
|
89
|
+
* Needs **two** permissions: a key with that scope, and the workspace having switched the action on.
|
|
90
|
+
*/
|
|
91
|
+
async proposedInvoice(input, idempotencyKey) {
|
|
92
|
+
return this.#exercise("kiipu.invoice_proposed", input, idempotencyKey);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Creates a reminder (a task with date and time) on a client named by name. Does not log a call: that is crm.call_logged. Does not create the client if it does not exist.
|
|
96
|
+
*
|
|
97
|
+
* `crm.task_created` v1 — scope `crm.task_created@1`.
|
|
98
|
+
*
|
|
99
|
+
* Needs **two** permissions: a key with that scope, and the workspace having switched the action on.
|
|
100
|
+
*/
|
|
101
|
+
async createdTask(input, idempotencyKey) {
|
|
102
|
+
return this.#exercise("crm.task_created", input, idempotencyKey);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Opens a new deal in the pipeline for a client named by name, with a title, an optional value in USD, an optional stage (by name; without it, the first one) and an optional owner. Does not check for other open deals: it returns how many remain so a duplicate is visible. Does not win or lose it: that is crm.stage_moved.
|
|
106
|
+
*
|
|
107
|
+
* `crm.deal_created` v1 — scope `crm.deal_created@1`.
|
|
108
|
+
*
|
|
109
|
+
* Needs **two** permissions: a key with that scope, and the workspace having switched the action on.
|
|
110
|
+
*/
|
|
111
|
+
async createdDeal(input, idempotencyKey) {
|
|
112
|
+
return this.#exercise("crm.deal_created", input, idempotencyKey);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Saves a note on a client's record, naming the client: something to know next time, with no call and no date. For a call use crm.call_logged; for a dated reminder, crm.task_created.
|
|
116
|
+
*
|
|
117
|
+
* `crm.note_added` v1 — scope `crm.note_added@1`.
|
|
118
|
+
*
|
|
119
|
+
* Needs **two** permissions: a key with that scope, and the workspace having switched the action on.
|
|
120
|
+
*/
|
|
121
|
+
async addedNote(input, idempotencyKey) {
|
|
122
|
+
return this.#exercise("crm.note_added", input, idempotencyKey);
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Adds a person (name, and optionally email, phone and role) to a client's record, naming the client. Does not make them the primary contact and does not create the client. If someone with that email or phone already existed, the reply says so but does not block it.
|
|
126
|
+
*
|
|
127
|
+
* `crm.contact_added` v1 — scope `crm.contact_added@1`.
|
|
128
|
+
*
|
|
129
|
+
* Needs **two** permissions: a key with that scope, and the workspace having switched the action on.
|
|
130
|
+
*/
|
|
131
|
+
async addedContact(input, idempotencyKey) {
|
|
132
|
+
return this.#exercise("crm.contact_added", input, idempotencyKey);
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Quotes sending the SAME WhatsApp message to several clients named by name (up to 50). Sends NOTHING: per client, it says whether the text goes as-is (24-hour window open, free), whether an approved template is needed and what it costs, or why that client cannot be messaged. Returns a signed quote valid for 15 minutes; to send, call miira.broadcast_sent with it. Show the quote to the person first.
|
|
136
|
+
*
|
|
137
|
+
* `miira.broadcast_quoted` v1 — scope `miira.broadcast_quoted@1`.
|
|
138
|
+
*
|
|
139
|
+
* Needs **two** permissions: a key with that scope, and the workspace having switched the action on.
|
|
140
|
+
*/
|
|
141
|
+
async quotedBroadcast(input, idempotencyKey) {
|
|
142
|
+
return this.#exercise("miira.broadcast_quoted", input, idempotencyKey);
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Sends the WhatsApp broadcast quoted by miira.broadcast_quoted, exactly to whom and how the quote said. If anything changed (window, consent, rate) it refuses with a new quote to confirm again. Costs money when templates are involved: do not call it without the person having seen the cost.
|
|
146
|
+
*
|
|
147
|
+
* `miira.broadcast_sent` v1 — scope `miira.broadcast_sent@1`.
|
|
148
|
+
*
|
|
149
|
+
* Needs **two** permissions: a key with that scope, and the workspace having switched the action on.
|
|
150
|
+
*/
|
|
151
|
+
async sentBroadcast(input, idempotencyKey) {
|
|
152
|
+
return this.#exercise("miira.broadcast_sent", input, idempotencyKey);
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Voids a DRAFT invoice (one created with kiipu.invoice_proposed and not yet issued), by its id or by the client's name when it is their only draft. Does not void issued invoices: that is for a person in Kiipu.
|
|
156
|
+
*
|
|
157
|
+
* `kiipu.draft_voided` v1 — scope `kiipu.draft_voided@1`.
|
|
158
|
+
*
|
|
159
|
+
* Needs **two** permissions: a key with that scope, and the workspace having switched the action on.
|
|
160
|
+
*/
|
|
161
|
+
async voidedDraft(input, idempotencyKey) {
|
|
162
|
+
return this.#exercise("kiipu.draft_voided", input, idempotencyKey);
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Leaves in the Kiipu approval queue the notice that a client (by name) paid a given amount of an open invoice. Does NOT apply the payment and touches no balances: a person checks it against the bank and applies it. If the client has several open invoices the number must be given.
|
|
166
|
+
*
|
|
167
|
+
* `kiipu.payment_reported` v1 — scope `kiipu.payment_reported@1`.
|
|
168
|
+
*
|
|
169
|
+
* Needs **two** permissions: a key with that scope, and the workspace having switched the action on.
|
|
170
|
+
*/
|
|
171
|
+
async reportedPayment(input, idempotencyKey) {
|
|
172
|
+
return this.#exercise("kiipu.payment_reported", input, idempotencyKey);
|
|
173
|
+
}
|
|
174
|
+
}
|
package/index.ts
ADDED
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
// GENERATED from the niiko action manifest — plan `6c3240a7b22d`. Do not edit by hand.
|
|
2
|
+
//
|
|
3
|
+
// Every method here exists because an action is DECLARED public. If the server answers `not_exposed`,
|
|
4
|
+
// this copy of the SDK is newer than the deployment — not that you got the name wrong.
|
|
5
|
+
|
|
6
|
+
/** The three outcomes. Branch once on `status` and you know where you are. */
|
|
7
|
+
export type Result<T> =
|
|
8
|
+
| { status: "done"; output: T; idempotencyKey: string }
|
|
9
|
+
/** Waits for a human signature and may complete hours later. You get notified by webhook. */
|
|
10
|
+
| { status: "pending_approval"; proposalId: string | null; autonomy: string }
|
|
11
|
+
/** Not done. `reason` is a named reason and `detail.message`, when present, says what to do. */
|
|
12
|
+
| { status: "refused"; reason: string; detail?: Record<string, unknown> };
|
|
13
|
+
|
|
14
|
+
export class NiikoError extends Error {
|
|
15
|
+
constructor(readonly status: number, readonly body: unknown) {
|
|
16
|
+
super(`niiko: the server answered ${status}`);
|
|
17
|
+
this.name = "NiikoError";
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface CreateLeadInput {
|
|
22
|
+
submissionId: string;
|
|
23
|
+
source: "web_form" | "referral" | "api" | "import" | "event" | "other";
|
|
24
|
+
name?: string;
|
|
25
|
+
email?: string;
|
|
26
|
+
phone?: string;
|
|
27
|
+
fields?: Record<string, unknown>;
|
|
28
|
+
consent?: { email: boolean; whatsapp: boolean; source: "api" | "web_form" | "verbal" | "llamada" | "visita" | "imported" };
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface CreateLeadOutput {
|
|
32
|
+
outcome: "created" | "existing" | "ambiguous" | "rejected";
|
|
33
|
+
clientId: string | null;
|
|
34
|
+
reason: "honeypot" | "invalid_email" | "disposable_email" | "invalid_identity" | null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** The reasons `miira.lead_create` declares. One outside this list is a server fault, not a state. */
|
|
38
|
+
export type CreateLeadReason = "honeypot" | "invalid_email" | "disposable_email" | "invalid_identity";
|
|
39
|
+
|
|
40
|
+
export interface LoggedCallInput {
|
|
41
|
+
client: string;
|
|
42
|
+
summary: string;
|
|
43
|
+
followUp?: { what: string; dueAt: string };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface LoggedCallOutput {
|
|
47
|
+
clientId: string;
|
|
48
|
+
clientName: string;
|
|
49
|
+
activityId: string;
|
|
50
|
+
followUpId: string | null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** The reasons `crm.call_logged` declares. One outside this list is a server fault, not a state. */
|
|
54
|
+
export type LoggedCallReason = "cliente_no_encontrado" | "cliente_ambiguo" | "demasiados_clientes" | "sin_permiso";
|
|
55
|
+
|
|
56
|
+
export interface AssignedOwnerInput {
|
|
57
|
+
client: string;
|
|
58
|
+
owner: string;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface AssignedOwnerOutput {
|
|
62
|
+
clientId: string;
|
|
63
|
+
clientName: string;
|
|
64
|
+
ownerUserId: string;
|
|
65
|
+
ownerName: string;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** The reasons `crm.owner_assigned` declares. One outside this list is a server fault, not a state. */
|
|
69
|
+
export type AssignedOwnerReason = "cliente_no_encontrado" | "cliente_ambiguo" | "demasiados_clientes" | "persona_no_encontrada" | "persona_ambigua" | "sin_permiso";
|
|
70
|
+
|
|
71
|
+
export interface MovedStageInput {
|
|
72
|
+
client: string;
|
|
73
|
+
stage: string;
|
|
74
|
+
lostReason?: string;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface MovedStageOutput {
|
|
78
|
+
dealId: string;
|
|
79
|
+
clientId: string;
|
|
80
|
+
clientName: string;
|
|
81
|
+
stageName: string;
|
|
82
|
+
won: boolean;
|
|
83
|
+
firstWon: boolean;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** The reasons `crm.stage_moved` declares. One outside this list is a server fault, not a state. */
|
|
87
|
+
export type MovedStageReason = "cliente_no_encontrado" | "cliente_ambiguo" | "demasiados_clientes" | "sin_negocio_abierto" | "varios_negocios" | "etapa_no_encontrada" | "negocio_cerrado" | "ya_en_esa_etapa" | "sin_permiso";
|
|
88
|
+
|
|
89
|
+
export interface ProposedInvoiceInput {
|
|
90
|
+
client: string;
|
|
91
|
+
lines: { concept: string; quantity: string; unitPriceUsd: string; tax: "exempt" | "itbms_7" | "itbms_10" | "itbms_15" }[];
|
|
92
|
+
dueAt?: string;
|
|
93
|
+
series?: string;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export interface ProposedInvoiceOutput {
|
|
97
|
+
invoiceId: string;
|
|
98
|
+
clientId: string;
|
|
99
|
+
clientName: string;
|
|
100
|
+
status: "draft";
|
|
101
|
+
subtotalUsd: string;
|
|
102
|
+
taxUsd: string;
|
|
103
|
+
totalUsd: string;
|
|
104
|
+
dueAt: string;
|
|
105
|
+
series: string;
|
|
106
|
+
issueAt: "/kiipu/facturas";
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** The reasons `kiipu.invoice_proposed` declares. One outside this list is a server fault, not a state. */
|
|
110
|
+
export type ProposedInvoiceReason = "cliente_no_encontrado" | "cliente_ambiguo" | "demasiados_clientes" | "sin_permiso";
|
|
111
|
+
|
|
112
|
+
export interface CreatedTaskInput {
|
|
113
|
+
client: string;
|
|
114
|
+
what: string;
|
|
115
|
+
dueAt: string;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export interface CreatedTaskOutput {
|
|
119
|
+
clientId: string;
|
|
120
|
+
clientName: string;
|
|
121
|
+
taskId: string;
|
|
122
|
+
dueAt: string;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** The reasons `crm.task_created` declares. One outside this list is a server fault, not a state. */
|
|
126
|
+
export type CreatedTaskReason = "cliente_no_encontrado" | "cliente_ambiguo" | "demasiados_clientes" | "sin_permiso";
|
|
127
|
+
|
|
128
|
+
export interface CreatedDealInput {
|
|
129
|
+
client: string;
|
|
130
|
+
title: string;
|
|
131
|
+
valueUsd?: string;
|
|
132
|
+
stage?: string;
|
|
133
|
+
owner?: string;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export interface CreatedDealOutput {
|
|
137
|
+
dealId: string;
|
|
138
|
+
clientId: string;
|
|
139
|
+
clientName: string;
|
|
140
|
+
title: string;
|
|
141
|
+
valueUsd: string | null;
|
|
142
|
+
stageName: string;
|
|
143
|
+
ownerName: string | null;
|
|
144
|
+
openDeals: number;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** The reasons `crm.deal_created` declares. One outside this list is a server fault, not a state. */
|
|
148
|
+
export type CreatedDealReason = "cliente_no_encontrado" | "cliente_ambiguo" | "demasiados_clientes" | "etapa_no_encontrada" | "etapa_cerrada" | "persona_no_encontrada" | "persona_ambigua" | "sin_permiso";
|
|
149
|
+
|
|
150
|
+
export interface AddedNoteInput {
|
|
151
|
+
client: string;
|
|
152
|
+
note: string;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export interface AddedNoteOutput {
|
|
156
|
+
clientId: string;
|
|
157
|
+
clientName: string;
|
|
158
|
+
noteId: string;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/** The reasons `crm.note_added` declares. One outside this list is a server fault, not a state. */
|
|
162
|
+
export type AddedNoteReason = "cliente_no_encontrado" | "cliente_ambiguo" | "demasiados_clientes" | "sin_permiso";
|
|
163
|
+
|
|
164
|
+
export interface AddedContactInput {
|
|
165
|
+
client: string;
|
|
166
|
+
name: string;
|
|
167
|
+
email?: string;
|
|
168
|
+
phone?: string;
|
|
169
|
+
role?: string;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export interface AddedContactOutput {
|
|
173
|
+
clientId: string;
|
|
174
|
+
clientName: string;
|
|
175
|
+
contactId: string;
|
|
176
|
+
possibleDuplicate: boolean;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/** The reasons `crm.contact_added` declares. One outside this list is a server fault, not a state. */
|
|
180
|
+
export type AddedContactReason = "cliente_no_encontrado" | "cliente_ambiguo" | "demasiados_clientes" | "sin_permiso";
|
|
181
|
+
|
|
182
|
+
export interface QuotedBroadcastInput {
|
|
183
|
+
clients: string[];
|
|
184
|
+
message: string;
|
|
185
|
+
template?: string;
|
|
186
|
+
templateValues?: string[];
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export interface QuotedBroadcastOutput {
|
|
190
|
+
rows: { client: string; clientId: string | null; clientName: string | null; outcome: "free_text" | "template" | "needs_template" | "no_phone" | "suppressed" | "consent_revoked" | "no_marketing_consent" | "quiet_hours" | "not_found" | "ambiguous" | "too_many"; costUsd: string | null; candidates: string[] }[];
|
|
191
|
+
totals: { freeText: number; template: number; skipped: number; costUsd: string };
|
|
192
|
+
quote: string | null;
|
|
193
|
+
expiresAt: string | null;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/** The reasons `miira.broadcast_quoted` declares. One outside this list is a server fault, not a state. */
|
|
197
|
+
export type QuotedBroadcastReason = "plantilla_invalida" | "tarifas_vencidas" | "sin_permiso";
|
|
198
|
+
|
|
199
|
+
export interface SentBroadcastInput {
|
|
200
|
+
quote: string;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export interface SentBroadcastOutput {
|
|
204
|
+
queued: { clientId: string; clientName: string; mode: "free_text" | "template"; outboxId: string }[];
|
|
205
|
+
costUsd: string;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/** The reasons `miira.broadcast_sent` declares. One outside this list is a server fault, not a state. */
|
|
209
|
+
export type SentBroadcastReason = "presupuesto_invalido" | "presupuesto_vencido" | "presupuesto_cambiado" | "plantilla_invalida" | "tarifas_vencidas" | "sin_permiso";
|
|
210
|
+
|
|
211
|
+
export interface VoidedDraftInput {
|
|
212
|
+
invoiceId?: string;
|
|
213
|
+
client?: string;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
export interface VoidedDraftOutput {
|
|
217
|
+
invoiceId: string;
|
|
218
|
+
clientId: string;
|
|
219
|
+
clientName: string;
|
|
220
|
+
totalUsd: string;
|
|
221
|
+
status: "void";
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/** The reasons `kiipu.draft_voided` declares. One outside this list is a server fault, not a state. */
|
|
225
|
+
export type VoidedDraftReason = "cliente_no_encontrado" | "cliente_ambiguo" | "demasiados_clientes" | "borrador_no_encontrado" | "varios_borradores" | "no_es_borrador" | "sin_permiso";
|
|
226
|
+
|
|
227
|
+
export interface ReportedPaymentInput {
|
|
228
|
+
client: string;
|
|
229
|
+
amountUsd: string;
|
|
230
|
+
invoice?: string;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export interface ReportedPaymentOutput {
|
|
234
|
+
submissionId: string;
|
|
235
|
+
clientId: string;
|
|
236
|
+
clientName: string;
|
|
237
|
+
invoiceId: string;
|
|
238
|
+
invoiceNumber: string;
|
|
239
|
+
outstandingUsd: string;
|
|
240
|
+
declaredUsd: string;
|
|
241
|
+
status: "received";
|
|
242
|
+
reviewAt: "/kiipu/aprobaciones";
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/** The reasons `kiipu.payment_reported` declares. One outside this list is a server fault, not a state. */
|
|
246
|
+
export type ReportedPaymentReason = "cliente_no_encontrado" | "cliente_ambiguo" | "demasiados_clientes" | "sin_factura_abierta" | "varias_facturas" | "factura_no_encontrada" | "sin_permiso";
|
|
247
|
+
|
|
248
|
+
export interface NiikoOptions {
|
|
249
|
+
/** The workspace API key. Shown ONCE, when created in Settings. */
|
|
250
|
+
apiKey: string;
|
|
251
|
+
baseUrl?: string;
|
|
252
|
+
fetch?: typeof fetch;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
export class Niiko {
|
|
256
|
+
#apiKey: string;
|
|
257
|
+
#baseUrl: string;
|
|
258
|
+
#fetch: typeof fetch;
|
|
259
|
+
|
|
260
|
+
constructor(o: NiikoOptions) {
|
|
261
|
+
if (!o.apiKey) throw new Error("niiko: apiKey is required");
|
|
262
|
+
this.#apiKey = o.apiKey;
|
|
263
|
+
this.#baseUrl = (o.baseUrl ?? "https://niiko.org").replace(/\/+$/, "");
|
|
264
|
+
this.#fetch = o.fetch ?? fetch;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
async #exercise<T>(action: string, body: unknown, idempotencyKey?: string): Promise<Result<T>> {
|
|
268
|
+
const r = await this.#fetch(`${this.#baseUrl}/api/v1/actions/${action}`, {
|
|
269
|
+
method: "POST",
|
|
270
|
+
headers: {
|
|
271
|
+
authorization: `Bearer ${this.#apiKey}`,
|
|
272
|
+
"content-type": "application/json",
|
|
273
|
+
// Send it WHENEVER you can: a timeout retry with the same key does not execute again.
|
|
274
|
+
...(idempotencyKey ? { "idempotency-key": idempotencyKey } : {}),
|
|
275
|
+
},
|
|
276
|
+
body: JSON.stringify(body),
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
const json = await r.json().catch(() => null);
|
|
280
|
+
// A refusal is NOT an exception: it is a product state, and the caller must be able to branch on it.
|
|
281
|
+
// What does throw is what cannot be read — there is no decision to make there.
|
|
282
|
+
if (json && typeof json === "object" && "status" in json) return json as Result<T>;
|
|
283
|
+
throw new NiikoError(r.status, json);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Creates a new lead in the workspace CRM from its contact details. If a matching one already exists it is not duplicated: the reply is `ambiguous` with the candidates.
|
|
288
|
+
*
|
|
289
|
+
* `miira.lead_create` v1 — scope `miira.lead_create@1`.
|
|
290
|
+
*
|
|
291
|
+
* Needs **two** permissions: a key with that scope, and the workspace having switched the action on.
|
|
292
|
+
*/
|
|
293
|
+
async createLead(input: CreateLeadInput, idempotencyKey?: string): Promise<Result<CreateLeadOutput>> {
|
|
294
|
+
return this.#exercise<CreateLeadOutput>("miira.lead_create", input, idempotencyKey);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Logs what was discussed in a call on a client's record, naming the client; optionally creates the follow-up with its date. Reads nothing and calls no one.
|
|
299
|
+
*
|
|
300
|
+
* `crm.call_logged` v1 — scope `crm.call_logged@1`.
|
|
301
|
+
*
|
|
302
|
+
* Needs **two** permissions: a key with that scope, and the workspace having switched the action on.
|
|
303
|
+
*/
|
|
304
|
+
async loggedCall(input: LoggedCallInput, idempotencyKey?: string): Promise<Result<LoggedCallOutput>> {
|
|
305
|
+
return this.#exercise<LoggedCallOutput>("crm.call_logged", input, idempotencyKey);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Changes who owns a client, naming the client and the team member (by name or email). If either is ambiguous it refuses with the list.
|
|
310
|
+
*
|
|
311
|
+
* `crm.owner_assigned` v1 — scope `crm.owner_assigned@1`.
|
|
312
|
+
*
|
|
313
|
+
* Needs **two** permissions: a key with that scope, and the workspace having switched the action on.
|
|
314
|
+
*/
|
|
315
|
+
async assignedOwner(input: AssignedOwnerInput, idempotencyKey?: string): Promise<Result<AssignedOwnerOutput>> {
|
|
316
|
+
return this.#exercise<AssignedOwnerOutput>("crm.owner_assigned", input, idempotencyKey);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Moves a client's open deal to another pipeline stage, naming the client and the stage. Creates no deals: with no open deal it refuses, and with several it refuses with the list.
|
|
321
|
+
*
|
|
322
|
+
* `crm.stage_moved` v1 — scope `crm.stage_moved@1`.
|
|
323
|
+
*
|
|
324
|
+
* Needs **two** permissions: a key with that scope, and the workspace having switched the action on.
|
|
325
|
+
*/
|
|
326
|
+
async movedStage(input: MovedStageInput, idempotencyKey?: string): Promise<Result<MovedStageOutput>> {
|
|
327
|
+
return this.#exercise<MovedStageOutput>("crm.stage_moved", input, idempotencyKey);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Prepares an invoice as a DRAFT for a client named by name, with its lines and taxes. Does NOT issue it, does NOT number it and does NOT count as debt: a person reviews and issues it in Kiipu. Does not create the client if it does not exist.
|
|
332
|
+
*
|
|
333
|
+
* `kiipu.invoice_proposed` v1 — scope `kiipu.invoice_proposed@1`.
|
|
334
|
+
*
|
|
335
|
+
* Needs **two** permissions: a key with that scope, and the workspace having switched the action on.
|
|
336
|
+
*/
|
|
337
|
+
async proposedInvoice(input: ProposedInvoiceInput, idempotencyKey?: string): Promise<Result<ProposedInvoiceOutput>> {
|
|
338
|
+
return this.#exercise<ProposedInvoiceOutput>("kiipu.invoice_proposed", input, idempotencyKey);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Creates a reminder (a task with date and time) on a client named by name. Does not log a call: that is crm.call_logged. Does not create the client if it does not exist.
|
|
343
|
+
*
|
|
344
|
+
* `crm.task_created` v1 — scope `crm.task_created@1`.
|
|
345
|
+
*
|
|
346
|
+
* Needs **two** permissions: a key with that scope, and the workspace having switched the action on.
|
|
347
|
+
*/
|
|
348
|
+
async createdTask(input: CreatedTaskInput, idempotencyKey?: string): Promise<Result<CreatedTaskOutput>> {
|
|
349
|
+
return this.#exercise<CreatedTaskOutput>("crm.task_created", input, idempotencyKey);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Opens a new deal in the pipeline for a client named by name, with a title, an optional value in USD, an optional stage (by name; without it, the first one) and an optional owner. Does not check for other open deals: it returns how many remain so a duplicate is visible. Does not win or lose it: that is crm.stage_moved.
|
|
354
|
+
*
|
|
355
|
+
* `crm.deal_created` v1 — scope `crm.deal_created@1`.
|
|
356
|
+
*
|
|
357
|
+
* Needs **two** permissions: a key with that scope, and the workspace having switched the action on.
|
|
358
|
+
*/
|
|
359
|
+
async createdDeal(input: CreatedDealInput, idempotencyKey?: string): Promise<Result<CreatedDealOutput>> {
|
|
360
|
+
return this.#exercise<CreatedDealOutput>("crm.deal_created", input, idempotencyKey);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Saves a note on a client's record, naming the client: something to know next time, with no call and no date. For a call use crm.call_logged; for a dated reminder, crm.task_created.
|
|
365
|
+
*
|
|
366
|
+
* `crm.note_added` v1 — scope `crm.note_added@1`.
|
|
367
|
+
*
|
|
368
|
+
* Needs **two** permissions: a key with that scope, and the workspace having switched the action on.
|
|
369
|
+
*/
|
|
370
|
+
async addedNote(input: AddedNoteInput, idempotencyKey?: string): Promise<Result<AddedNoteOutput>> {
|
|
371
|
+
return this.#exercise<AddedNoteOutput>("crm.note_added", input, idempotencyKey);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Adds a person (name, and optionally email, phone and role) to a client's record, naming the client. Does not make them the primary contact and does not create the client. If someone with that email or phone already existed, the reply says so but does not block it.
|
|
376
|
+
*
|
|
377
|
+
* `crm.contact_added` v1 — scope `crm.contact_added@1`.
|
|
378
|
+
*
|
|
379
|
+
* Needs **two** permissions: a key with that scope, and the workspace having switched the action on.
|
|
380
|
+
*/
|
|
381
|
+
async addedContact(input: AddedContactInput, idempotencyKey?: string): Promise<Result<AddedContactOutput>> {
|
|
382
|
+
return this.#exercise<AddedContactOutput>("crm.contact_added", input, idempotencyKey);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Quotes sending the SAME WhatsApp message to several clients named by name (up to 50). Sends NOTHING: per client, it says whether the text goes as-is (24-hour window open, free), whether an approved template is needed and what it costs, or why that client cannot be messaged. Returns a signed quote valid for 15 minutes; to send, call miira.broadcast_sent with it. Show the quote to the person first.
|
|
387
|
+
*
|
|
388
|
+
* `miira.broadcast_quoted` v1 — scope `miira.broadcast_quoted@1`.
|
|
389
|
+
*
|
|
390
|
+
* Needs **two** permissions: a key with that scope, and the workspace having switched the action on.
|
|
391
|
+
*/
|
|
392
|
+
async quotedBroadcast(input: QuotedBroadcastInput, idempotencyKey?: string): Promise<Result<QuotedBroadcastOutput>> {
|
|
393
|
+
return this.#exercise<QuotedBroadcastOutput>("miira.broadcast_quoted", input, idempotencyKey);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* Sends the WhatsApp broadcast quoted by miira.broadcast_quoted, exactly to whom and how the quote said. If anything changed (window, consent, rate) it refuses with a new quote to confirm again. Costs money when templates are involved: do not call it without the person having seen the cost.
|
|
398
|
+
*
|
|
399
|
+
* `miira.broadcast_sent` v1 — scope `miira.broadcast_sent@1`.
|
|
400
|
+
*
|
|
401
|
+
* Needs **two** permissions: a key with that scope, and the workspace having switched the action on.
|
|
402
|
+
*/
|
|
403
|
+
async sentBroadcast(input: SentBroadcastInput, idempotencyKey?: string): Promise<Result<SentBroadcastOutput>> {
|
|
404
|
+
return this.#exercise<SentBroadcastOutput>("miira.broadcast_sent", input, idempotencyKey);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* Voids a DRAFT invoice (one created with kiipu.invoice_proposed and not yet issued), by its id or by the client's name when it is their only draft. Does not void issued invoices: that is for a person in Kiipu.
|
|
409
|
+
*
|
|
410
|
+
* `kiipu.draft_voided` v1 — scope `kiipu.draft_voided@1`.
|
|
411
|
+
*
|
|
412
|
+
* Needs **two** permissions: a key with that scope, and the workspace having switched the action on.
|
|
413
|
+
*/
|
|
414
|
+
async voidedDraft(input: VoidedDraftInput, idempotencyKey?: string): Promise<Result<VoidedDraftOutput>> {
|
|
415
|
+
return this.#exercise<VoidedDraftOutput>("kiipu.draft_voided", input, idempotencyKey);
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* Leaves in the Kiipu approval queue the notice that a client (by name) paid a given amount of an open invoice. Does NOT apply the payment and touches no balances: a person checks it against the bank and applies it. If the client has several open invoices the number must be given.
|
|
420
|
+
*
|
|
421
|
+
* `kiipu.payment_reported` v1 — scope `kiipu.payment_reported@1`.
|
|
422
|
+
*
|
|
423
|
+
* Needs **two** permissions: a key with that scope, and the workspace having switched the action on.
|
|
424
|
+
*/
|
|
425
|
+
async reportedPayment(input: ReportedPaymentInput, idempotencyKey?: string): Promise<Result<ReportedPaymentOutput>> {
|
|
426
|
+
return this.#exercise<ReportedPaymentOutput>("kiipu.payment_reported", input, idempotencyKey);
|
|
427
|
+
}
|
|
428
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vorluno/niiko-sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Generated client for the niiko actions API — it exposes verbs, not rows.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"default": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc",
|
|
16
|
+
"prepublishOnly": "tsc"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"typescript": "^5.6.0"
|
|
20
|
+
},
|
|
21
|
+
"license": "Apache-2.0",
|
|
22
|
+
"author": "Vorluno (https://vorluno.dev)",
|
|
23
|
+
"homepage": "https://developers.niiko.org",
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "git+https://github.com/vorluno/niiko-sdk-typescript.git"
|
|
27
|
+
},
|
|
28
|
+
"bugs": {
|
|
29
|
+
"url": "https://github.com/vorluno/niiko-sdk-typescript/issues"
|
|
30
|
+
},
|
|
31
|
+
"keywords": [
|
|
32
|
+
"niiko",
|
|
33
|
+
"api",
|
|
34
|
+
"sdk",
|
|
35
|
+
"crm",
|
|
36
|
+
"leads"
|
|
37
|
+
],
|
|
38
|
+
"files": [
|
|
39
|
+
"dist",
|
|
40
|
+
"index.ts",
|
|
41
|
+
"README.md",
|
|
42
|
+
"LICENSE"
|
|
43
|
+
],
|
|
44
|
+
"dependencies": {},
|
|
45
|
+
"engines": {
|
|
46
|
+
"node": ">=18"
|
|
47
|
+
}
|
|
48
|
+
}
|