@zoplio/sdk-js 0.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/README.md ADDED
@@ -0,0 +1,107 @@
1
+ # @zoplio/sdk-js
2
+
3
+ Official Zoplio Node.js/TypeScript SDK for the [Zoplio API v1](../../docs/quickstart.md). MIT licensed.
4
+
5
+ Zoplio schedules meetings for you: you say who and roughly when, Zoplio negotiates with every participant over WhatsApp/email and confirms a slot.
6
+
7
+ Requires Node.js >= 18 (uses the global `fetch`).
8
+
9
+ ## Install
10
+
11
+ Not yet published to npm — consumed from this monorepo. Build with `npm run build` in this package.
12
+
13
+ ## Usage
14
+
15
+ ```ts
16
+ import { ZoplioClient, ZoplioApiError } from '@zoplio/sdk-js';
17
+
18
+ const zoplio = new ZoplioClient({
19
+ apiKey: process.env.ZOPLIO_API_KEY!, // zpl_...
20
+ // baseUrl: 'https://api.zoplio.com' (default)
21
+ });
22
+
23
+ // Create a meeting — Zoplio reaches out to participants and negotiates.
24
+ const created = await zoplio.scheduleMeeting(
25
+ {
26
+ title: 'Intro call',
27
+ durationMinutes: 30,
28
+ participants: [
29
+ { email: 'petr@example.com', name: 'Petr' },
30
+ { phone: '+420777123456', name: 'Jana' },
31
+ ],
32
+ preferredDate: '2026-06-15',
33
+ preferredTime: '14:00',
34
+ timezone: 'Europe/Prague',
35
+ },
36
+ { idempotencyKey: 'order-42-intro-call' }, // optional, safe retries
37
+ );
38
+ console.log(created.meetingId, created.status, created.proposedSlots);
39
+
40
+ // Poll status (or use webhooks instead).
41
+ const meeting = await zoplio.getMeeting(created.meetingId);
42
+
43
+ // List / reschedule / cancel.
44
+ await zoplio.listMeetings({ status: 'confirmed', limit: 10 });
45
+ await zoplio.rescheduleMeeting(created.meetingId, {
46
+ preferredDate: '2026-06-16',
47
+ preferredTime: '10:00',
48
+ timezone: 'Europe/Prague',
49
+ });
50
+ await zoplio.cancelMeeting(created.meetingId);
51
+ ```
52
+
53
+ ## Errors
54
+
55
+ Every non-2xx response throws `ZoplioApiError` with the contract envelope:
56
+
57
+ ```ts
58
+ try {
59
+ await zoplio.getMeeting('nope');
60
+ } catch (err) {
61
+ if (err instanceof ZoplioApiError) {
62
+ err.status; // 404
63
+ err.code; // 'not_found' | 'unauthorized' | 'rate_limited' | 'validation_failed' | 'conflict' | 'upstream_error'
64
+ err.message; // human-readable
65
+ err.details; // [{ field, message }] on validation_failed
66
+ }
67
+ }
68
+ ```
69
+
70
+ ## Webhooks
71
+
72
+ ```ts
73
+ // Subscribe — the secret is returned exactly once.
74
+ const hook = await zoplio.createWebhook({
75
+ url: 'https://example.com/zoplio-hook',
76
+ events: ['meeting.confirmed', 'meeting.cancelled'],
77
+ });
78
+ saveSecret(hook.secret); // whsec_...
79
+
80
+ await zoplio.listWebhooks();
81
+ await zoplio.deleteWebhook(hook.id);
82
+ ```
83
+
84
+ Verify deliveries with the static helper — pass the RAW request body:
85
+
86
+ ```ts
87
+ import express from 'express';
88
+
89
+ app.post('/zoplio-hook', express.raw({ type: 'application/json' }), (req, res) => {
90
+ const ok = ZoplioClient.verifyWebhookSignature(
91
+ req.body, // raw Buffer
92
+ req.header('X-Zoplio-Signature') ?? '',
93
+ process.env.ZOPLIO_WEBHOOK_SECRET!, // whsec_...
94
+ );
95
+ if (!ok) return res.status(401).end();
96
+ const { event, payload, timestamp } = JSON.parse(req.body.toString('utf8'));
97
+ // event also arrives in the X-Zoplio-Event header
98
+ res.status(200).end();
99
+ });
100
+ ```
101
+
102
+ ## Development
103
+
104
+ ```bash
105
+ npm run typecheck # tsc --noEmit
106
+ npm run build # emit dist/
107
+ ```
@@ -0,0 +1,91 @@
1
+ import { ApiErrorCode, CancelMeetingResult, CreateWebhookParams, DeleteWebhookResult, FieldDetail, ListMeetingsParams, ListMeetingsResult, ListWebhooksResult, MeetingDetail, RescheduleMeetingParams, RescheduleMeetingResult, ScheduleMeetingOptions, ScheduleMeetingParams, ScheduleMeetingResult, WebhookCreated, ZoplioConfig } from './types';
2
+ /**
3
+ * Error thrown for every non-2xx API response. Carries the contract error
4
+ * envelope: `{ error: { code, message, details? } }`.
5
+ */
6
+ export declare class ZoplioApiError extends Error {
7
+ /** Contract error code, e.g. `validation_failed`, `rate_limited`. */
8
+ readonly code: ApiErrorCode;
9
+ /** HTTP status of the response. */
10
+ readonly status: number;
11
+ /** Per-field details on `validation_failed` errors. */
12
+ readonly details?: FieldDetail[];
13
+ constructor(status: number, code: ApiErrorCode, message: string, details?: FieldDetail[]);
14
+ }
15
+ /**
16
+ * Client for the Zoplio public API v1.
17
+ *
18
+ * ```ts
19
+ * const zoplio = new ZoplioClient({ apiKey: process.env.ZOPLIO_API_KEY! });
20
+ * const { meetingId } = await zoplio.scheduleMeeting({
21
+ * title: 'Intro call',
22
+ * participants: [{ email: 'petr@example.com' }],
23
+ * });
24
+ * ```
25
+ *
26
+ * Requires a `fetch` global (Node.js >= 18).
27
+ */
28
+ export declare class ZoplioClient {
29
+ private readonly apiKey;
30
+ private readonly baseUrl;
31
+ constructor(config: ZoplioConfig);
32
+ private request;
33
+ /**
34
+ * Create a meeting and start negotiating with the participants.
35
+ * `POST /v1/meetings`
36
+ */
37
+ scheduleMeeting(params: ScheduleMeetingParams, options?: ScheduleMeetingOptions): Promise<ScheduleMeetingResult>;
38
+ /**
39
+ * Fetch one meeting you organize, with per-participant status.
40
+ * `GET /v1/meetings/:id`
41
+ */
42
+ getMeeting(meetingId: string): Promise<MeetingDetail>;
43
+ /**
44
+ * List meetings you organize, newest first.
45
+ * `GET /v1/meetings?status=&limit=`
46
+ */
47
+ listMeetings(params?: ListMeetingsParams): Promise<ListMeetingsResult>;
48
+ /**
49
+ * Cancel a meeting (idempotent — cancelling twice still returns `cancelled`).
50
+ * `POST /v1/meetings/:id/cancel`
51
+ */
52
+ cancelMeeting(meetingId: string): Promise<CancelMeetingResult>;
53
+ /**
54
+ * Propose a new exact date+time to all participants.
55
+ * `POST /v1/meetings/:id/reschedule`
56
+ *
57
+ * Throws `ZoplioApiError` with code `conflict` when the requested time
58
+ * collides with a participant's availability, when the negotiation state
59
+ * does not allow re-proposing, or when the negotiation ran out of rounds -
60
+ * in that last case the meeting has been cancelled and every participant
61
+ * told. Throws code `validation_failed` when the requested time is already
62
+ * in the past; nothing changed and nobody was contacted.
63
+ */
64
+ rescheduleMeeting(meetingId: string, params: RescheduleMeetingParams): Promise<RescheduleMeetingResult>;
65
+ /**
66
+ * Subscribe a URL to meeting lifecycle events. The returned `secret`
67
+ * (whsec_...) is shown exactly once — store it to verify deliveries.
68
+ * `POST /v1/webhooks`
69
+ */
70
+ createWebhook(params: CreateWebhookParams): Promise<WebhookCreated>;
71
+ /**
72
+ * List your webhook subscriptions (without secrets).
73
+ * `GET /v1/webhooks`
74
+ */
75
+ listWebhooks(): Promise<ListWebhooksResult>;
76
+ /**
77
+ * Delete one of your webhook subscriptions.
78
+ * `DELETE /v1/webhooks/:id`
79
+ */
80
+ deleteWebhook(webhookId: string): Promise<DeleteWebhookResult>;
81
+ /**
82
+ * Verify a webhook delivery: constant-time comparison of the
83
+ * `X-Zoplio-Signature` header against HMAC-SHA256(secret, rawBody),
84
+ * hex-encoded — exactly how Zoplio signs deliveries.
85
+ *
86
+ * Pass the RAW request body bytes/string (before any JSON parsing —
87
+ * re-serializing the parsed body may not be byte-identical).
88
+ */
89
+ static verifyWebhookSignature(rawBody: string | Uint8Array, signatureHeader: string, secret: string): boolean;
90
+ }
91
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AACA,OAAO,EACL,YAAY,EACZ,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACnB,WAAW,EACX,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,EAClB,aAAa,EACb,uBAAuB,EACvB,uBAAuB,EACvB,sBAAsB,EACtB,qBAAqB,EACrB,qBAAqB,EACrB,cAAc,EACd,YAAY,EACb,MAAM,SAAS,CAAC;AAEjB;;;GAGG;AACH,qBAAa,cAAe,SAAQ,KAAK;IACvC,qEAAqE;IACrE,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,mCAAmC;IACnC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,uDAAuD;IACvD,QAAQ,CAAC,OAAO,CAAC,EAAE,WAAW,EAAE,CAAC;gBAErB,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,EAAE;CAOzF;AAMD;;;;;;;;;;;;GAYG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,MAAM,EAAE,YAAY;YAQlB,OAAO;IAqCrB;;;OAGG;IACG,eAAe,CACnB,MAAM,EAAE,qBAAqB,EAC7B,OAAO,CAAC,EAAE,sBAAsB,GAC/B,OAAO,CAAC,qBAAqB,CAAC;IAOjC;;;OAGG;IACG,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAI3D;;;OAGG;IACG,YAAY,CAAC,MAAM,GAAE,kBAAuB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAQhF;;;OAGG;IACG,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAIpE;;;;;;;;;;OAUG;IACG,iBAAiB,CACrB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,uBAAuB,GAC9B,OAAO,CAAC,uBAAuB,CAAC;IAMnC;;;;OAIG;IACG,aAAa,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,cAAc,CAAC;IAIzE;;;OAGG;IACG,YAAY,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAIjD;;;OAGG;IACG,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAIpE;;;;;;;OAOG;IACH,MAAM,CAAC,sBAAsB,CAC3B,OAAO,EAAE,MAAM,GAAG,UAAU,EAC5B,eAAe,EAAE,MAAM,EACvB,MAAM,EAAE,MAAM,GACb,OAAO;CASX"}
package/dist/client.js ADDED
@@ -0,0 +1,167 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ZoplioClient = exports.ZoplioApiError = void 0;
4
+ const crypto_1 = require("crypto");
5
+ /**
6
+ * Error thrown for every non-2xx API response. Carries the contract error
7
+ * envelope: `{ error: { code, message, details? } }`.
8
+ */
9
+ class ZoplioApiError extends Error {
10
+ /** Contract error code, e.g. `validation_failed`, `rate_limited`. */
11
+ code;
12
+ /** HTTP status of the response. */
13
+ status;
14
+ /** Per-field details on `validation_failed` errors. */
15
+ details;
16
+ constructor(status, code, message, details) {
17
+ super(message);
18
+ this.name = 'ZoplioApiError';
19
+ this.status = status;
20
+ this.code = code;
21
+ this.details = details;
22
+ }
23
+ }
24
+ exports.ZoplioApiError = ZoplioApiError;
25
+ /**
26
+ * Client for the Zoplio public API v1.
27
+ *
28
+ * ```ts
29
+ * const zoplio = new ZoplioClient({ apiKey: process.env.ZOPLIO_API_KEY! });
30
+ * const { meetingId } = await zoplio.scheduleMeeting({
31
+ * title: 'Intro call',
32
+ * participants: [{ email: 'petr@example.com' }],
33
+ * });
34
+ * ```
35
+ *
36
+ * Requires a `fetch` global (Node.js >= 18).
37
+ */
38
+ class ZoplioClient {
39
+ apiKey;
40
+ baseUrl;
41
+ constructor(config) {
42
+ if (!config || typeof config.apiKey !== 'string' || config.apiKey.length === 0) {
43
+ throw new Error('ZoplioClient requires an apiKey (zpl_...)');
44
+ }
45
+ this.apiKey = config.apiKey;
46
+ this.baseUrl = (config.baseUrl || 'https://api.zoplio.com').replace(/\/+$/, '');
47
+ }
48
+ async request(method, path, body, extraHeaders) {
49
+ const res = await fetch(`${this.baseUrl}${path}`, {
50
+ method,
51
+ headers: {
52
+ 'Content-Type': 'application/json',
53
+ Authorization: `Bearer ${this.apiKey}`,
54
+ ...extraHeaders,
55
+ },
56
+ body: body ? JSON.stringify(body) : undefined,
57
+ });
58
+ let data;
59
+ try {
60
+ data = await res.json();
61
+ }
62
+ catch {
63
+ data = undefined;
64
+ }
65
+ if (!res.ok) {
66
+ const err = data?.error;
67
+ throw new ZoplioApiError(res.status, err?.code ?? 'upstream_error', err?.message ?? `Zoplio API error: HTTP ${res.status}`, err?.details);
68
+ }
69
+ return data;
70
+ }
71
+ // ── Meetings ───────────────────────────────────────────────────────
72
+ /**
73
+ * Create a meeting and start negotiating with the participants.
74
+ * `POST /v1/meetings`
75
+ */
76
+ async scheduleMeeting(params, options) {
77
+ const headers = options?.idempotencyKey
78
+ ? { 'X-Idempotency-Key': options.idempotencyKey }
79
+ : undefined;
80
+ return this.request('POST', '/v1/meetings', params, headers);
81
+ }
82
+ /**
83
+ * Fetch one meeting you organize, with per-participant status.
84
+ * `GET /v1/meetings/:id`
85
+ */
86
+ async getMeeting(meetingId) {
87
+ return this.request('GET', `/v1/meetings/${encodeURIComponent(meetingId)}`);
88
+ }
89
+ /**
90
+ * List meetings you organize, newest first.
91
+ * `GET /v1/meetings?status=&limit=`
92
+ */
93
+ async listMeetings(params = {}) {
94
+ const query = new URLSearchParams();
95
+ if (params.status)
96
+ query.set('status', params.status);
97
+ if (params.limit !== undefined)
98
+ query.set('limit', String(params.limit));
99
+ const qs = query.toString();
100
+ return this.request('GET', `/v1/meetings${qs ? `?${qs}` : ''}`);
101
+ }
102
+ /**
103
+ * Cancel a meeting (idempotent — cancelling twice still returns `cancelled`).
104
+ * `POST /v1/meetings/:id/cancel`
105
+ */
106
+ async cancelMeeting(meetingId) {
107
+ return this.request('POST', `/v1/meetings/${encodeURIComponent(meetingId)}/cancel`);
108
+ }
109
+ /**
110
+ * Propose a new exact date+time to all participants.
111
+ * `POST /v1/meetings/:id/reschedule`
112
+ *
113
+ * Throws `ZoplioApiError` with code `conflict` when the requested time
114
+ * collides with a participant's availability, when the negotiation state
115
+ * does not allow re-proposing, or when the negotiation ran out of rounds -
116
+ * in that last case the meeting has been cancelled and every participant
117
+ * told. Throws code `validation_failed` when the requested time is already
118
+ * in the past; nothing changed and nobody was contacted.
119
+ */
120
+ async rescheduleMeeting(meetingId, params) {
121
+ return this.request('POST', `/v1/meetings/${encodeURIComponent(meetingId)}/reschedule`, params);
122
+ }
123
+ // ── Webhooks ───────────────────────────────────────────────────────
124
+ /**
125
+ * Subscribe a URL to meeting lifecycle events. The returned `secret`
126
+ * (whsec_...) is shown exactly once — store it to verify deliveries.
127
+ * `POST /v1/webhooks`
128
+ */
129
+ async createWebhook(params) {
130
+ return this.request('POST', '/v1/webhooks', params);
131
+ }
132
+ /**
133
+ * List your webhook subscriptions (without secrets).
134
+ * `GET /v1/webhooks`
135
+ */
136
+ async listWebhooks() {
137
+ return this.request('GET', '/v1/webhooks');
138
+ }
139
+ /**
140
+ * Delete one of your webhook subscriptions.
141
+ * `DELETE /v1/webhooks/:id`
142
+ */
143
+ async deleteWebhook(webhookId) {
144
+ return this.request('DELETE', `/v1/webhooks/${encodeURIComponent(webhookId)}`);
145
+ }
146
+ /**
147
+ * Verify a webhook delivery: constant-time comparison of the
148
+ * `X-Zoplio-Signature` header against HMAC-SHA256(secret, rawBody),
149
+ * hex-encoded — exactly how Zoplio signs deliveries.
150
+ *
151
+ * Pass the RAW request body bytes/string (before any JSON parsing —
152
+ * re-serializing the parsed body may not be byte-identical).
153
+ */
154
+ static verifyWebhookSignature(rawBody, signatureHeader, secret) {
155
+ if (!signatureHeader || !secret)
156
+ return false;
157
+ const expected = (0, crypto_1.createHmac)('sha256', secret).update(rawBody).digest('hex');
158
+ const provided = signatureHeader.trim().toLowerCase();
159
+ const a = Buffer.from(expected, 'utf8');
160
+ const b = Buffer.from(provided, 'utf8');
161
+ if (a.length !== b.length)
162
+ return false;
163
+ return (0, crypto_1.timingSafeEqual)(a, b);
164
+ }
165
+ }
166
+ exports.ZoplioClient = ZoplioClient;
167
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export { ZoplioClient, ZoplioApiError } from './client';
2
+ export * from './types';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AACxD,cAAc,SAAS,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.ZoplioApiError = exports.ZoplioClient = void 0;
18
+ var client_1 = require("./client");
19
+ Object.defineProperty(exports, "ZoplioClient", { enumerable: true, get: function () { return client_1.ZoplioClient; } });
20
+ Object.defineProperty(exports, "ZoplioApiError", { enumerable: true, get: function () { return client_1.ZoplioApiError; } });
21
+ __exportStar(require("./types"), exports);
22
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,mCAAwD;AAA/C,sGAAA,YAAY,OAAA;AAAE,wGAAA,cAAc,OAAA;AACrC,0CAAwB"}
@@ -0,0 +1,166 @@
1
+ /**
2
+ * Wire types for the Zoplio public API v1 (served by api-gateway under /v1).
3
+ * Shapes mirror apps/api-gateway/src — these are the exact JSON bodies on the
4
+ * wire, not internal models.
5
+ */
6
+ export interface ZoplioConfig {
7
+ /** API key, format `zpl_<hex>`. Sent as `Authorization: Bearer zpl_...`. */
8
+ apiKey: string;
9
+ /** API origin. Defaults to `https://api.zoplio.com`. */
10
+ baseUrl?: string;
11
+ }
12
+ /** Error codes used by every non-2xx response. */
13
+ export type ApiErrorCode = 'unauthorized' | 'rate_limited' | 'validation_failed' | 'not_found' | 'conflict' | 'quota_exceeded' | 'upstream_error';
14
+ /** Per-field validation detail attached to `validation_failed` errors. */
15
+ export interface FieldDetail {
16
+ field: string;
17
+ message: string;
18
+ }
19
+ export type MeetingStatus = 'draft' | 'negotiating' | 'confirmed' | 'cancelled' | 'rescheduling';
20
+ /** Public webhook event names — the only events delivered to subscribers. */
21
+ export type WebhookEvent = 'meeting.created' | 'meeting.confirmed' | 'meeting.cancelled' | 'negotiation.failed';
22
+ /** A concrete time slot. ISO 8601 datetimes (UTC). */
23
+ export interface Slot {
24
+ start: string;
25
+ end: string;
26
+ }
27
+ /** Meeting participant input — each entry needs `phone` (E.164) or `email`. */
28
+ export interface ParticipantInput {
29
+ /** E.164 phone number, e.g. `+420777123456`. */
30
+ phone?: string;
31
+ email?: string;
32
+ /** Display name, max 200 chars. */
33
+ name?: string;
34
+ }
35
+ export interface ScheduleMeetingParams {
36
+ /** Max 300 chars. Defaults to "Meeting" server-side. */
37
+ title?: string;
38
+ /** Integer 5..1440. Defaults to 30 server-side. */
39
+ durationMinutes?: number;
40
+ /** 1..8 participants, each with a phone or an email. */
41
+ participants: ParticipantInput[];
42
+ /** YYYY-MM-DD. Required when `preferredTime` is set. */
43
+ preferredDate?: string;
44
+ /** HH:MM (24h). */
45
+ preferredTime?: string;
46
+ /** IANA timezone the preferredDate/preferredTime are expressed in. */
47
+ timezone?: string;
48
+ /** YYYY-MM-DD. */
49
+ earliestDate?: string;
50
+ /** YYYY-MM-DD. */
51
+ latestDate?: string;
52
+ /** Ask participants for their availability instead of proposing slots. */
53
+ openAsk?: boolean;
54
+ /** Max 500 chars. Omitting it makes the meeting virtual. */
55
+ location?: string;
56
+ /** Set `false` for meetings the organizer does not attend. */
57
+ organizerAttending?: boolean;
58
+ }
59
+ export interface ScheduleMeetingOptions {
60
+ /**
61
+ * Sent as `X-Idempotency-Key` (1-128 chars). Replaying the same key
62
+ * returns the originally created meeting instead of creating a duplicate.
63
+ */
64
+ idempotencyKey?: string;
65
+ }
66
+ export interface ScheduleMeetingResult {
67
+ meetingId: string;
68
+ negotiationId: string;
69
+ /** `negotiating` on fresh creates; an idempotent replay returns the real status. */
70
+ status: MeetingStatus;
71
+ proposedSlots: Slot[];
72
+ }
73
+ export interface MeetingParticipant {
74
+ name?: string;
75
+ email?: string;
76
+ phone?: string;
77
+ /** e.g. `pending`, `accepted`, `declined`, `counter-proposed`. */
78
+ status: string;
79
+ attending: boolean;
80
+ }
81
+ export interface MeetingDetail {
82
+ id: string;
83
+ title: string;
84
+ status: MeetingStatus;
85
+ confirmedSlot?: Slot;
86
+ participants: MeetingParticipant[];
87
+ }
88
+ export interface MeetingSummary {
89
+ id: string;
90
+ title: string;
91
+ status: MeetingStatus;
92
+ confirmedSlot?: Slot;
93
+ createdAt?: string;
94
+ }
95
+ export interface ListMeetingsParams {
96
+ status?: MeetingStatus;
97
+ /** 1..50, default 20. */
98
+ limit?: number;
99
+ }
100
+ export interface ListMeetingsResult {
101
+ meetings: MeetingSummary[];
102
+ }
103
+ export interface CancelMeetingResult {
104
+ status: 'cancelled';
105
+ }
106
+ export interface RescheduleMeetingParams {
107
+ /** YYYY-MM-DD. Required. */
108
+ preferredDate: string;
109
+ /** HH:MM (24h). Required. */
110
+ preferredTime: string;
111
+ /** IANA timezone the date/time are expressed in. */
112
+ timezone?: string;
113
+ }
114
+ export interface RescheduleMeetingResult {
115
+ meetingId: string;
116
+ status: 'negotiating';
117
+ proposedSlots: Slot[];
118
+ }
119
+ export interface CreateWebhookParams {
120
+ /** Public http(s) endpoint. Private/internal hosts are rejected. */
121
+ url: string;
122
+ /** Defaults to all four events when omitted. */
123
+ events?: WebhookEvent[];
124
+ }
125
+ export interface WebhookCreated {
126
+ id: string;
127
+ url: string;
128
+ events: WebhookEvent[];
129
+ /** `whsec_` signing secret — returned exactly once, at creation. */
130
+ secret: string;
131
+ }
132
+ export interface WebhookSummary {
133
+ id: string;
134
+ url: string;
135
+ events: string[];
136
+ active: boolean;
137
+ createdAt?: string;
138
+ }
139
+ export interface ListWebhooksResult {
140
+ webhooks: WebhookSummary[];
141
+ }
142
+ export interface DeleteWebhookResult {
143
+ deleted: true;
144
+ }
145
+ /**
146
+ * Body of every webhook delivery POSTed to a subscribed URL. Verify the
147
+ * `X-Zoplio-Signature` header over the RAW request body with
148
+ * `ZoplioClient.verifyWebhookSignature` before trusting it.
149
+ */
150
+ export interface WebhookDeliveryBody {
151
+ event: WebhookEvent;
152
+ payload: {
153
+ meetingId?: string;
154
+ organizerUserId?: string;
155
+ title?: string;
156
+ /** Present on confirmed/cancelled/failed events. */
157
+ negotiationId?: string;
158
+ participantEmails?: string[];
159
+ /** Present on meeting.confirmed. */
160
+ confirmedSlot?: Slot;
161
+ [key: string]: unknown;
162
+ };
163
+ /** ISO 8601 delivery timestamp. */
164
+ timestamp: string;
165
+ }
166
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ /**
3
+ * Wire types for the Zoplio public API v1 (served by api-gateway under /v1).
4
+ * Shapes mirror apps/api-gateway/src — these are the exact JSON bodies on the
5
+ * wire, not internal models.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";AAAA;;;;GAIG"}
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@zoplio/sdk-js",
3
+ "version": "0.2.0",
4
+ "description": "Official Zoplio Node.js/TypeScript SDK for the Zoplio API v1 (MIT)",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "default": "./dist/index.js"
11
+ }
12
+ },
13
+ "files": [
14
+ "dist",
15
+ "README.md",
16
+ "LICENSE"
17
+ ],
18
+ "engines": {
19
+ "node": ">=18"
20
+ },
21
+ "scripts": {
22
+ "build": "tsc",
23
+ "typecheck": "tsc --noEmit",
24
+ "test": "npx --yes tsx@4.19.2 --test \"src/**/__tests__/*.test.ts\"",
25
+ "prepublishOnly": "npm run build"
26
+ },
27
+ "license": "MIT",
28
+ "type": "commonjs",
29
+ "publishConfig": {
30
+ "access": "public"
31
+ },
32
+ "devDependencies": {
33
+ "@types/node": "^25.5.0",
34
+ "typescript": "^6.0.2"
35
+ },
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "https://github.com/Zoplio/zoplio-sdk.git",
39
+ "directory": "packages/sdk-js"
40
+ },
41
+ "homepage": "https://github.com/Zoplio/zoplio-sdk#readme",
42
+ "bugs": "https://github.com/Zoplio/zoplio-sdk/issues",
43
+ "keywords": [
44
+ "zoplio",
45
+ "scheduling",
46
+ "ai-agent",
47
+ "meetings",
48
+ "mcp"
49
+ ]
50
+ }