@medalsocial/sdk 1.6.0 → 1.7.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 +68 -0
- package/dist/openapi/medal-social.openapi.json +3097 -1489
- package/dist/pilot/index.d.mts +2 -2
- package/dist/pilot/index.d.ts +2 -2
- package/dist/src/index.d.mts +593 -23
- package/dist/src/index.d.ts +593 -23
- package/dist/src/index.js +472 -146
- package/dist/src/index.js.map +1 -1
- package/dist/src/index.mjs +471 -146
- package/dist/src/index.mjs.map +1 -1
- package/dist/src/openapi.generated.d.mts +905 -45
- package/dist/src/openapi.generated.d.ts +905 -45
- package/dist/src/openapi.generated.js.map +1 -1
- package/openapi/medal-social.openapi.yaml +944 -0
- package/package.json +18 -17
- package/skills/client/SKILL.md +2 -2
- package/skills/resources/SKILL.md +104 -3
package/README.md
CHANGED
|
@@ -204,6 +204,74 @@ const { data: removed } = await medal.deals.remove(deal.id);
|
|
|
204
204
|
console.log(updated.success, unlinked.success, removed.success);
|
|
205
205
|
```
|
|
206
206
|
|
|
207
|
+
### Bookings
|
|
208
|
+
|
|
209
|
+
Money is always **integer øre** (`amount_ore`, `price_ore`) — never a float, never kroner. Timestamps come back as ISO 8601 strings; on the way in, either Unix milliseconds or an ISO string is accepted.
|
|
210
|
+
|
|
211
|
+
```ts
|
|
212
|
+
// Catalogue + free slots
|
|
213
|
+
const { data: services } = await medal.bookings.listServices();
|
|
214
|
+
const { data: resources } = await medal.bookings.listResources();
|
|
215
|
+
const { data: slots } = await medal.bookings.availability({
|
|
216
|
+
service_id: services[0].id,
|
|
217
|
+
from_ts: Date.now(),
|
|
218
|
+
to_ts: Date.now() + 7 * 86_400_000,
|
|
219
|
+
resource_id: resources[0].id, // optional — defaults to every capable resource
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
// Book a party — all items succeed or none do (max 50)
|
|
223
|
+
const { data: created } = await medal.bookings.create(
|
|
224
|
+
{
|
|
225
|
+
items: [
|
|
226
|
+
{ service_id: services[0].id, start_ts: slots[0].start_ts! },
|
|
227
|
+
{ service_id: services[0].id, start_ts: slots[1].start_ts!, booked_for_name: 'Ida', booked_for_birth_year: 2018 },
|
|
228
|
+
],
|
|
229
|
+
contact: { phone: '+4790000000', email: 'ida@example.com', name: 'Ida Hansen' },
|
|
230
|
+
notes: 'Bursdag',
|
|
231
|
+
},
|
|
232
|
+
{ idempotencyKey: crypto.randomUUID() }, // optional — see the note below
|
|
233
|
+
);
|
|
234
|
+
// created.bookings[i].manage_token is returned EXACTLY ONCE (only its hash is
|
|
235
|
+
// stored, and an idempotent replay omits it) — persist it for the manage link.
|
|
236
|
+
// It is UNRECOVERABLE if lost: `Booking` has no token field, so re-reading the
|
|
237
|
+
// booking gives you nothing. Reschedule to mint a fresh one, or act by id.
|
|
238
|
+
|
|
239
|
+
// Staff actions — policy windows are bypassed, cancels attributed to staff
|
|
240
|
+
const { data: booking } = await medal.bookings.get(created.bookings[0].id);
|
|
241
|
+
await medal.bookings.update(booking.id, { internal_notes: 'Allergisk mot parfyme' });
|
|
242
|
+
await medal.bookings.cancel(booking.id, { reason: 'Sykdom' });
|
|
243
|
+
const { data: moved } = await medal.bookings.reschedule(booking.id, {
|
|
244
|
+
new_start_ts: '2026-09-02T09:00:00.000Z',
|
|
245
|
+
new_resource_id: resources[0].id,
|
|
246
|
+
});
|
|
247
|
+
// moved.booking_id is a NEW id with a NEW manage_token — the old booking is cancelled
|
|
248
|
+
await medal.bookings.markNoShow(moved.booking_id);
|
|
249
|
+
|
|
250
|
+
// Listing — check `truncated`: when true, matching bookings exist that no
|
|
251
|
+
// cursor reaches, so narrow the from_ts/to_ts window
|
|
252
|
+
const page = await medal.bookings.list({ status: 'confirmed', from_ts: Date.now(), limit: 50 });
|
|
253
|
+
console.log(page.pagination.has_more, page.pagination.next_cursor, page.pagination.truncated);
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
**Customer actions go through `medal.bookings.manage`**, keyed by the manage token instead of the booking id. This is not the same route with a different lookup key: the workspace's cancel/reschedule windows are **enforced**, and the cancel is attributed to the customer. Use it to relay a customer's own click on the link in their confirmation email.
|
|
257
|
+
|
|
258
|
+
```ts
|
|
259
|
+
const { data: summary } = await medal.bookings.manage.get(manageToken);
|
|
260
|
+
if (summary.can_cancel) await medal.bookings.manage.cancel(manageToken, { reason: 'Endret plan' });
|
|
261
|
+
if (summary.can_reschedule) {
|
|
262
|
+
const { data } = await medal.bookings.manage.reschedule(manageToken, {
|
|
263
|
+
new_start_ts: '2026-09-02T09:00:00.000Z',
|
|
264
|
+
});
|
|
265
|
+
console.log(data.booking_id, data.manage_token); // old token stops working
|
|
266
|
+
}
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
`can_cancel` / `can_reschedule` already apply the policy windows — honour them rather than re-deriving from `cancel_window_hours`.
|
|
270
|
+
|
|
271
|
+
**Booking writes are idempotent by default.** The SDK retries 429/5xx automatically, so every booking `POST` (`create`, `cancel`, `reschedule`, `markNoShow`, and both `manage` writes) carries a generated `Idempotency-Key` — a retry after a gateway failure replays the original result instead of booking the slot twice. Supply your own `options.idempotencyKey` to extend that guarantee across *your* retries too: the server remembers a key for 24 hours, keyed by `(key, workspace, method + path)`.
|
|
272
|
+
|
|
273
|
+
`update(id, input)` requires at least one of `notes` / `internal_notes`; `update(id, {})` is a compile error, matching the API's own 400.
|
|
274
|
+
|
|
207
275
|
### GDPR
|
|
208
276
|
|
|
209
277
|
```ts
|