@purveyors/sdk 0.3.0 → 0.4.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/dist/index.d.ts CHANGED
@@ -115,14 +115,14 @@ interface paths {
115
115
  patch?: never;
116
116
  trace?: never;
117
117
  };
118
- "/v1/catalog/access": {
118
+ "/v1/api-keys": {
119
119
  parameters: {
120
120
  query?: never;
121
121
  header?: never;
122
122
  path?: never;
123
123
  cookie?: never;
124
124
  };
125
- /** Catalog capabilities and visibility for the caller */
125
+ /** List API keys for the authenticated user */
126
126
  get: {
127
127
  parameters: {
128
128
  query?: never;
@@ -132,13 +132,22 @@ interface paths {
132
132
  };
133
133
  requestBody?: never;
134
134
  responses: {
135
- /** @description Resolved catalog access policy for the caller's principal */
135
+ /** @description API keys owned by the authenticated user */
136
136
  200: {
137
137
  headers: {
138
138
  [name: string]: unknown;
139
139
  };
140
140
  content: {
141
- "application/json": components["schemas"]["CatalogAccessResponse"];
141
+ "application/json": components["schemas"]["ApiKeyListResponse"];
142
+ };
143
+ };
144
+ /** @description Invalid API-key request */
145
+ 400: {
146
+ headers: {
147
+ [name: string]: unknown;
148
+ };
149
+ content: {
150
+ "application/json": components["schemas"]["ErrorResponse"];
142
151
  };
143
152
  };
144
153
  /** @description Authentication required */
@@ -159,81 +168,60 @@ interface paths {
159
168
  "application/json": components["schemas"]["ErrorResponse"];
160
169
  };
161
170
  };
171
+ /** @description API key not found for the authenticated user */
172
+ 404: {
173
+ headers: {
174
+ [name: string]: unknown;
175
+ };
176
+ content: {
177
+ "application/json": components["schemas"]["ErrorResponse"];
178
+ };
179
+ };
180
+ /** @description API key storage is unavailable */
181
+ 503: {
182
+ headers: {
183
+ [name: string]: unknown;
184
+ };
185
+ content: {
186
+ "application/json": components["schemas"]["ErrorResponse"];
187
+ };
188
+ };
162
189
  };
163
190
  };
164
191
  put?: never;
165
- post?: never;
166
- delete?: never;
167
- options?: never;
168
- head?: never;
169
- patch?: never;
170
- trace?: never;
171
- };
172
- "/v1/catalog": {
173
- parameters: {
174
- query?: never;
175
- header?: never;
176
- path?: never;
177
- cookie?: never;
178
- };
179
- /**
180
- * List public catalog coffees
181
- * @description Public catalog listing. Excludes wholesale-restricted rows and returns only public fields. API-key callers are capped to their plan's per-call row limit. Requesting entitlement-gated params (price/score ranges, process facets, advanced sorts) you are not entitled to is handled per PADR-0013 §7: strict callers (API keys, bearer-session JWTs) receive a 401/403; lenient callers (anonymous, first-party web) get the params stripped with a `meta.notices` entry. Send `Prefer: handling=strict` to opt into strict enforcement; `Prefer: handling=lenient` is honored only for callers already lenient-eligible and cannot downgrade a strict caller's enforcement.
182
- */
183
- get: {
192
+ /** Create an API key for the authenticated user */
193
+ post: {
184
194
  parameters: {
185
- query?: {
186
- page?: number;
187
- limit?: number;
188
- stocked?: "true" | "false" | "all";
189
- sort?: string;
190
- order?: "asc" | "desc";
191
- showWholesale?: "true" | "false";
192
- wholesaleOnly?: "true" | "false";
193
- origin?: string;
194
- continent?: string;
195
- country?: string | string[];
196
- region?: string;
197
- source?: string | string[];
198
- name?: string;
199
- processing?: string;
200
- variety?: string;
201
- type?: string;
202
- grade?: string;
203
- appearance?: string;
204
- supplier?: string;
205
- dryingMethod?: string;
206
- flavorKeywords?: string | string[];
207
- arrivalDate?: string;
208
- stockedDate?: string;
209
- stockedDays?: number;
210
- coffeeIds?: string;
211
- scoreValueMin?: number | null;
212
- scoreValueMax?: number | null;
213
- pricePerLbMin?: number | null;
214
- pricePerLbMax?: number | null;
215
- processing_base_method?: string;
216
- fermentation_type?: string;
217
- process_additive?: string;
218
- has_additives?: "true" | "false";
219
- processing_disclosure_level?: string;
220
- processing_confidence_min?: number | null;
221
- };
222
- header?: {
223
- Prefer?: string;
224
- };
195
+ query?: never;
196
+ header?: never;
225
197
  path?: never;
226
198
  cookie?: never;
227
199
  };
228
- requestBody?: never;
200
+ requestBody: {
201
+ content: {
202
+ "application/json": {
203
+ name: string;
204
+ scopes?: "catalog:read"[];
205
+ };
206
+ };
207
+ };
229
208
  responses: {
230
- /** @description A page of public catalog rows with pagination + meta */
231
- 200: {
209
+ /** @description API key created. The raw key is returned only once. */
210
+ 201: {
232
211
  headers: {
233
212
  [name: string]: unknown;
234
213
  };
235
214
  content: {
236
- "application/json": components["schemas"]["CatalogListResponse"];
215
+ "application/json": components["schemas"]["ApiKeyCreateResponse"];
216
+ };
217
+ };
218
+ /** @description Invalid API-key request */
219
+ 400: {
220
+ headers: {
221
+ [name: string]: unknown;
222
+ };
223
+ content: {
224
+ "application/json": components["schemas"]["ErrorResponse"];
237
225
  };
238
226
  };
239
227
  /** @description Authentication required */
@@ -254,77 +242,70 @@ interface paths {
254
242
  "application/json": components["schemas"]["ErrorResponse"];
255
243
  };
256
244
  };
245
+ /** @description API key not found for the authenticated user */
246
+ 404: {
247
+ headers: {
248
+ [name: string]: unknown;
249
+ };
250
+ content: {
251
+ "application/json": components["schemas"]["ErrorResponse"];
252
+ };
253
+ };
254
+ /** @description API key storage is unavailable */
255
+ 503: {
256
+ headers: {
257
+ [name: string]: unknown;
258
+ };
259
+ content: {
260
+ "application/json": components["schemas"]["ErrorResponse"];
261
+ };
262
+ };
257
263
  };
258
264
  };
259
- put?: never;
260
- post?: never;
261
265
  delete?: never;
262
266
  options?: never;
263
267
  head?: never;
264
268
  patch?: never;
265
269
  trace?: never;
266
270
  };
267
- "/v1/catalog/facets": {
271
+ "/v1/api-keys/{id}": {
268
272
  parameters: {
269
273
  query?: never;
270
274
  header?: never;
271
275
  path?: never;
272
276
  cookie?: never;
273
277
  };
274
- /**
275
- * Catalog filter metadata and counted facets
276
- * @description Returns access-aware catalog filter metadata. Values are computed after visibility and entitled content filters are applied; premium process metadata is included only for member sessions and paid API tiers. Requesting entitlement-gated filters you are not entitled to is handled per PADR-0013 §7: strict callers (API keys, bearer-session JWTs) receive a 401/403; lenient callers (anonymous, first-party web) get the filters stripped with a `meta.notices` entry. Send `Prefer: handling=strict` to opt into strict enforcement; `Prefer: handling=lenient` is honored only for callers already lenient-eligible and cannot downgrade a strict caller's enforcement.
277
- */
278
- get: {
278
+ get?: never;
279
+ put?: never;
280
+ post?: never;
281
+ /** Revoke an API key owned by the authenticated user */
282
+ delete: {
279
283
  parameters: {
280
- query?: {
281
- stocked?: "true" | "false" | "all";
282
- showWholesale?: "true" | "false";
283
- wholesaleOnly?: "true" | "false";
284
- origin?: string;
285
- continent?: string;
286
- country?: string | string[];
287
- region?: string;
288
- source?: string | string[];
289
- name?: string;
290
- processing?: string;
291
- variety?: string;
292
- type?: string;
293
- grade?: string;
294
- appearance?: string;
295
- supplier?: string;
296
- dryingMethod?: string;
297
- flavorKeywords?: string | string[];
298
- arrivalDate?: string;
299
- stockedDate?: string;
300
- stockedDays?: number;
301
- coffeeIds?: string | string[];
302
- scoreValueMin?: number | null;
303
- scoreValueMax?: number | null;
304
- pricePerLbMin?: number | null;
305
- pricePerLbMax?: number | null;
306
- processing_base_method?: string;
307
- fermentation_type?: string;
308
- process_additive?: string;
309
- has_additives?: "true" | "false";
310
- processing_disclosure_level?: string;
311
- processing_confidence_min?: number | null;
312
- };
313
- header?: {
314
- Prefer?: string;
284
+ query?: never;
285
+ header?: never;
286
+ path: {
287
+ id: string;
315
288
  };
316
- path?: never;
317
289
  cookie?: never;
318
290
  };
319
291
  requestBody?: never;
320
292
  responses: {
321
- /** @description Access-aware catalog filter metadata */
293
+ /** @description API key revoked */
322
294
  200: {
323
295
  headers: {
324
296
  [name: string]: unknown;
325
297
  };
326
298
  content: {
327
- "application/json": components["schemas"]["CatalogFacetsResponse"];
299
+ "application/json": components["schemas"]["ApiKeyMutationResponse"];
300
+ };
301
+ };
302
+ /** @description Invalid API-key request */
303
+ 400: {
304
+ headers: {
305
+ [name: string]: unknown;
306
+ };
307
+ content: {
308
+ "application/json": components["schemas"]["ErrorResponse"];
328
309
  };
329
310
  };
330
311
  /** @description Authentication required */
@@ -345,46 +326,68 @@ interface paths {
345
326
  "application/json": components["schemas"]["ErrorResponse"];
346
327
  };
347
328
  };
329
+ /** @description API key not found for the authenticated user */
330
+ 404: {
331
+ headers: {
332
+ [name: string]: unknown;
333
+ };
334
+ content: {
335
+ "application/json": components["schemas"]["ErrorResponse"];
336
+ };
337
+ };
338
+ /** @description API key storage is unavailable */
339
+ 503: {
340
+ headers: {
341
+ [name: string]: unknown;
342
+ };
343
+ content: {
344
+ "application/json": components["schemas"]["ErrorResponse"];
345
+ };
346
+ };
348
347
  };
349
348
  };
350
- put?: never;
351
- post?: never;
352
- delete?: never;
353
349
  options?: never;
354
350
  head?: never;
355
351
  patch?: never;
356
352
  trace?: never;
357
353
  };
358
- "/v1/catalog/origin-price-stats": {
354
+ "/v1/api-keys/{id}/rotate": {
359
355
  parameters: {
360
356
  query?: never;
361
357
  header?: never;
362
358
  path?: never;
363
359
  cookie?: never;
364
360
  };
365
- /**
366
- * Live catalog price context by origin
367
- * @description Returns per-origin live catalog price percentiles over the caller-visible stocked catalog. Used by first-party surfaces to compare a lot's visible display price against origin peers.
368
- */
369
- get: {
361
+ get?: never;
362
+ put?: never;
363
+ /** Rotate an API key owned by the authenticated user */
364
+ post: {
370
365
  parameters: {
371
- query?: {
372
- showWholesale?: "true" | "false";
373
- wholesaleOnly?: "true" | "false";
374
- };
366
+ query?: never;
375
367
  header?: never;
376
- path?: never;
368
+ path: {
369
+ id: string;
370
+ };
377
371
  cookie?: never;
378
372
  };
379
373
  requestBody?: never;
380
374
  responses: {
381
- /** @description Per-origin price context for caller-visible catalog rows */
382
- 200: {
375
+ /** @description Old API key revoked and replacement created. The raw replacement key is returned only once. */
376
+ 201: {
383
377
  headers: {
384
378
  [name: string]: unknown;
385
379
  };
386
380
  content: {
387
- "application/json": components["schemas"]["CatalogOriginPriceStatsResponse"];
381
+ "application/json": components["schemas"]["ApiKeyCreateResponse"];
382
+ };
383
+ };
384
+ /** @description Invalid API-key request */
385
+ 400: {
386
+ headers: {
387
+ [name: string]: unknown;
388
+ };
389
+ content: {
390
+ "application/json": components["schemas"]["ErrorResponse"];
388
391
  };
389
392
  };
390
393
  /** @description Authentication required */
@@ -405,27 +408,40 @@ interface paths {
405
408
  "application/json": components["schemas"]["ErrorResponse"];
406
409
  };
407
410
  };
411
+ /** @description API key not found for the authenticated user */
412
+ 404: {
413
+ headers: {
414
+ [name: string]: unknown;
415
+ };
416
+ content: {
417
+ "application/json": components["schemas"]["ErrorResponse"];
418
+ };
419
+ };
420
+ /** @description API key storage is unavailable */
421
+ 503: {
422
+ headers: {
423
+ [name: string]: unknown;
424
+ };
425
+ content: {
426
+ "application/json": components["schemas"]["ErrorResponse"];
427
+ };
428
+ };
408
429
  };
409
430
  };
410
- put?: never;
411
- post?: never;
412
431
  delete?: never;
413
432
  options?: never;
414
433
  head?: never;
415
434
  patch?: never;
416
435
  trace?: never;
417
436
  };
418
- "/v1/catalog/proof-coverage": {
437
+ "/v1/catalog/access": {
419
438
  parameters: {
420
439
  query?: never;
421
440
  header?: never;
422
441
  path?: never;
423
442
  cookie?: never;
424
443
  };
425
- /**
426
- * Aggregate proof-coverage over the public catalog
427
- * @description Aggregate-only proof coverage (no row-level evidence) computed over the stocked public catalog.
428
- */
444
+ /** Catalog capabilities and visibility for the caller */
429
445
  get: {
430
446
  parameters: {
431
447
  query?: never;
@@ -435,13 +451,13 @@ interface paths {
435
451
  };
436
452
  requestBody?: never;
437
453
  responses: {
438
- /** @description Proof-coverage summary with per-family buckets and gaps */
454
+ /** @description Resolved catalog access policy for the caller's principal */
439
455
  200: {
440
456
  headers: {
441
457
  [name: string]: unknown;
442
458
  };
443
459
  content: {
444
- "application/json": components["schemas"]["CatalogProofCoverageResponse"];
460
+ "application/json": components["schemas"]["CatalogAccessResponse"];
445
461
  };
446
462
  };
447
463
  /** @description Authentication required */
@@ -472,7 +488,7 @@ interface paths {
472
488
  patch?: never;
473
489
  trace?: never;
474
490
  };
475
- "/v1/price-index": {
491
+ "/v1/catalog": {
476
492
  parameters: {
477
493
  query?: never;
478
494
  header?: never;
@@ -480,34 +496,63 @@ interface paths {
480
496
  cookie?: never;
481
497
  };
482
498
  /**
483
- * Parchment Price Index (aggregate snapshots)
484
- * @description Aggregate-only price index over price_index_snapshots. Requires an API key with Parchment Intelligence (ppiAccess).
499
+ * List public catalog coffees
500
+ * @description Public catalog listing. Excludes wholesale-restricted rows and returns only public fields. API-key callers are capped to their plan's per-call row limit. Requesting entitlement-gated params (price/score ranges, process facets, advanced sorts) you are not entitled to is handled per PADR-0013 §7: strict callers (API keys, bearer-session JWTs) receive a 401/403; lenient callers (anonymous, first-party web) get the params stripped with a `meta.notices` entry. Send `Prefer: handling=strict` to opt into strict enforcement; `Prefer: handling=lenient` is honored only for callers already lenient-eligible and cannot downgrade a strict caller's enforcement.
485
501
  */
486
502
  get: {
487
503
  parameters: {
488
504
  query?: {
489
505
  page?: number;
490
506
  limit?: number;
507
+ stocked?: "true" | "false" | "all";
508
+ sort?: string;
509
+ order?: "asc" | "desc";
510
+ showWholesale?: "true" | "false";
511
+ wholesaleOnly?: "true" | "false";
491
512
  origin?: string;
492
- process?: string;
513
+ continent?: string;
514
+ country?: string | string[];
515
+ region?: string;
516
+ source?: string | string[];
517
+ name?: string;
518
+ processing?: string;
519
+ variety?: string;
520
+ type?: string;
493
521
  grade?: string;
494
- from?: string;
495
- to?: string;
496
- wholesale?: "true" | "false";
522
+ appearance?: string;
523
+ supplier?: string;
524
+ dryingMethod?: string;
525
+ flavorKeywords?: string | string[];
526
+ arrivalDate?: string;
527
+ stockedDate?: string;
528
+ stockedDays?: number;
529
+ coffeeIds?: string;
530
+ scoreValueMin?: number | null;
531
+ scoreValueMax?: number | null;
532
+ pricePerLbMin?: number | null;
533
+ pricePerLbMax?: number | null;
534
+ processing_base_method?: string;
535
+ fermentation_type?: string;
536
+ process_additive?: string;
537
+ has_additives?: "true" | "false";
538
+ processing_disclosure_level?: string;
539
+ processing_confidence_min?: number | null;
540
+ };
541
+ header?: {
542
+ Prefer?: string;
497
543
  };
498
- header?: never;
499
544
  path?: never;
500
545
  cookie?: never;
501
546
  };
502
547
  requestBody?: never;
503
548
  responses: {
504
- /** @description A page of aggregate price-index snapshots */
549
+ /** @description A page of public catalog rows with pagination + meta */
505
550
  200: {
506
551
  headers: {
507
552
  [name: string]: unknown;
508
553
  };
509
554
  content: {
510
- "application/json": components["schemas"]["PriceIndexResponse"];
555
+ "application/json": components["schemas"]["CatalogListResponse"];
511
556
  };
512
557
  };
513
558
  /** @description Authentication required */
@@ -538,7 +583,7 @@ interface paths {
538
583
  patch?: never;
539
584
  trace?: never;
540
585
  };
541
- "/v1/catalog/{id}/similar": {
586
+ "/v1/catalog/facets": {
542
587
  parameters: {
543
588
  query?: never;
544
589
  header?: never;
@@ -546,41 +591,59 @@ interface paths {
546
591
  cookie?: never;
547
592
  };
548
593
  /**
549
- * Find catalog coffees similar to a target coffee
550
- * @description Vector-similarity matches for a target catalog coffee, with deterministic identity gating, supplier-diversity re-ranking, and a canonical/similar split. Requires the bean-matching capability (a member session or a paid API plan).
594
+ * Catalog filter metadata and counted facets
595
+ * @description Returns access-aware catalog filter metadata. Values are computed after visibility and entitled content filters are applied; premium process metadata is included only for member sessions and paid API tiers. Requesting entitlement-gated filters you are not entitled to is handled per PADR-0013 §7: strict callers (API keys, bearer-session JWTs) receive a 401/403; lenient callers (anonymous, first-party web) get the filters stripped with a `meta.notices` entry. Send `Prefer: handling=strict` to opt into strict enforcement; `Prefer: handling=lenient` is honored only for callers already lenient-eligible and cannot downgrade a strict caller's enforcement.
551
596
  */
552
597
  get: {
553
598
  parameters: {
554
599
  query?: {
555
- threshold?: string;
556
- limit?: number;
557
- stocked_only?: "true" | "false";
558
- mode?: "all" | "likely_same" | "similar_profile";
600
+ stocked?: "true" | "false" | "all";
601
+ showWholesale?: "true" | "false";
602
+ wholesaleOnly?: "true" | "false";
603
+ origin?: string;
604
+ continent?: string;
605
+ country?: string | string[];
606
+ region?: string;
607
+ source?: string | string[];
608
+ name?: string;
609
+ processing?: string;
610
+ variety?: string;
611
+ type?: string;
612
+ grade?: string;
613
+ appearance?: string;
614
+ supplier?: string;
615
+ dryingMethod?: string;
616
+ flavorKeywords?: string | string[];
617
+ arrivalDate?: string;
618
+ stockedDate?: string;
619
+ stockedDays?: number;
620
+ coffeeIds?: string | string[];
621
+ scoreValueMin?: number | null;
622
+ scoreValueMax?: number | null;
623
+ pricePerLbMin?: number | null;
624
+ pricePerLbMax?: number | null;
625
+ processing_base_method?: string;
626
+ fermentation_type?: string;
627
+ process_additive?: string;
628
+ has_additives?: "true" | "false";
629
+ processing_disclosure_level?: string;
630
+ processing_confidence_min?: number | null;
559
631
  };
560
- header?: never;
561
- path: {
562
- id: string;
632
+ header?: {
633
+ Prefer?: string;
563
634
  };
635
+ path?: never;
564
636
  cookie?: never;
565
637
  };
566
638
  requestBody?: never;
567
639
  responses: {
568
- /** @description Target coffee with grouped similarity matches */
640
+ /** @description Access-aware catalog filter metadata */
569
641
  200: {
570
642
  headers: {
571
643
  [name: string]: unknown;
572
644
  };
573
645
  content: {
574
- "application/json": components["schemas"]["CatalogSimilarityResponse"];
575
- };
576
- };
577
- /** @description Invalid path id or query parameter */
578
- 400: {
579
- headers: {
580
- [name: string]: unknown;
581
- };
582
- content: {
583
- "application/json": components["schemas"]["ErrorResponse"];
646
+ "application/json": components["schemas"]["CatalogFacetsResponse"];
584
647
  };
585
648
  };
586
649
  /** @description Authentication required */
@@ -601,15 +664,6 @@ interface paths {
601
664
  "application/json": components["schemas"]["ErrorResponse"];
602
665
  };
603
666
  };
604
- /** @description Catalog coffee not found */
605
- 404: {
606
- headers: {
607
- [name: string]: unknown;
608
- };
609
- content: {
610
- "application/json": components["schemas"]["ErrorResponse"];
611
- };
612
- };
613
667
  };
614
668
  };
615
669
  put?: never;
@@ -620,7 +674,7 @@ interface paths {
620
674
  patch?: never;
621
675
  trace?: never;
622
676
  };
623
- "/v1/procurement/briefs": {
677
+ "/v1/catalog/origin-price-stats": {
624
678
  parameters: {
625
679
  query?: never;
626
680
  header?: never;
@@ -628,25 +682,28 @@ interface paths {
628
682
  cookie?: never;
629
683
  };
630
684
  /**
631
- * List saved sourcing briefs
632
- * @description List the authenticated principal's active sourcing briefs. Requires a member session or a paid (member+) API plan; API keys also need the catalog:read scope.
685
+ * Live catalog price context by origin
686
+ * @description Returns per-origin live catalog price percentiles over the caller-visible stocked catalog. Used by first-party surfaces to compare a lot's visible display price against origin peers.
633
687
  */
634
688
  get: {
635
689
  parameters: {
636
- query?: never;
690
+ query?: {
691
+ showWholesale?: "true" | "false";
692
+ wholesaleOnly?: "true" | "false";
693
+ };
637
694
  header?: never;
638
695
  path?: never;
639
696
  cookie?: never;
640
697
  };
641
698
  requestBody?: never;
642
699
  responses: {
643
- /** @description The principal's active sourcing briefs */
700
+ /** @description Per-origin price context for caller-visible catalog rows */
644
701
  200: {
645
702
  headers: {
646
703
  [name: string]: unknown;
647
704
  };
648
705
  content: {
649
- "application/json": components["schemas"]["SourcingBriefsListResponse"];
706
+ "application/json": components["schemas"]["CatalogOriginPriceStatsResponse"];
650
707
  };
651
708
  };
652
709
  /** @description Authentication required */
@@ -670,39 +727,40 @@ interface paths {
670
727
  };
671
728
  };
672
729
  put?: never;
730
+ post?: never;
731
+ delete?: never;
732
+ options?: never;
733
+ head?: never;
734
+ patch?: never;
735
+ trace?: never;
736
+ };
737
+ "/v1/catalog/proof-coverage": {
738
+ parameters: {
739
+ query?: never;
740
+ header?: never;
741
+ path?: never;
742
+ cookie?: never;
743
+ };
673
744
  /**
674
- * Create a sourcing brief
675
- * @description Create a saved sourcing brief for the authenticated principal. Requires a member session or a paid (member+) API plan; API keys also need the catalog:read scope.
745
+ * Aggregate proof-coverage over the public catalog
746
+ * @description Aggregate-only proof coverage (no row-level evidence) computed over the stocked public catalog.
676
747
  */
677
- post: {
748
+ get: {
678
749
  parameters: {
679
750
  query?: never;
680
751
  header?: never;
681
752
  path?: never;
682
753
  cookie?: never;
683
754
  };
684
- requestBody?: {
685
- content: {
686
- "application/json": components["schemas"]["SourcingBriefCreateRequest"];
687
- };
688
- };
755
+ requestBody?: never;
689
756
  responses: {
690
- /** @description The created sourcing brief */
691
- 201: {
692
- headers: {
693
- [name: string]: unknown;
694
- };
695
- content: {
696
- "application/json": components["schemas"]["SourcingBriefResponse"];
697
- };
698
- };
699
- /** @description Invalid request body or unsupported criteria */
700
- 400: {
757
+ /** @description Proof-coverage summary with per-family buckets and gaps */
758
+ 200: {
701
759
  headers: {
702
760
  [name: string]: unknown;
703
761
  };
704
762
  content: {
705
- "application/json": components["schemas"]["ErrorResponse"];
763
+ "application/json": components["schemas"]["CatalogProofCoverageResponse"];
706
764
  };
707
765
  };
708
766
  /** @description Authentication required */
@@ -725,13 +783,15 @@ interface paths {
725
783
  };
726
784
  };
727
785
  };
786
+ put?: never;
787
+ post?: never;
728
788
  delete?: never;
729
789
  options?: never;
730
790
  head?: never;
731
791
  patch?: never;
732
792
  trace?: never;
733
793
  };
734
- "/v1/procurement/briefs/{id}": {
794
+ "/v1/price-index": {
735
795
  parameters: {
736
796
  query?: never;
737
797
  header?: never;
@@ -739,27 +799,34 @@ interface paths {
739
799
  cookie?: never;
740
800
  };
741
801
  /**
742
- * Get a sourcing brief
743
- * @description Fetch one of the authenticated principal's sourcing briefs by id. Requires a member session or a paid (member+) API plan; API keys also need the catalog:read scope.
802
+ * Parchment Price Index (aggregate snapshots)
803
+ * @description Aggregate-only price index over price_index_snapshots. Requires an API key with Parchment Intelligence (ppiAccess).
744
804
  */
745
805
  get: {
746
806
  parameters: {
747
- query?: never;
748
- header?: never;
749
- path: {
750
- id: string;
807
+ query?: {
808
+ page?: number;
809
+ limit?: number;
810
+ origin?: string;
811
+ process?: string;
812
+ grade?: string;
813
+ from?: string;
814
+ to?: string;
815
+ wholesale?: "true" | "false";
751
816
  };
817
+ header?: never;
818
+ path?: never;
752
819
  cookie?: never;
753
820
  };
754
821
  requestBody?: never;
755
822
  responses: {
756
- /** @description The requested sourcing brief */
823
+ /** @description A page of aggregate price-index snapshots */
757
824
  200: {
758
825
  headers: {
759
826
  [name: string]: unknown;
760
827
  };
761
828
  content: {
762
- "application/json": components["schemas"]["SourcingBriefResponse"];
829
+ "application/json": components["schemas"]["PriceIndexResponse"];
763
830
  };
764
831
  };
765
832
  /** @description Authentication required */
@@ -780,15 +847,6 @@ interface paths {
780
847
  "application/json": components["schemas"]["ErrorResponse"];
781
848
  };
782
849
  };
783
- /** @description No such brief for this principal */
784
- 404: {
785
- headers: {
786
- [name: string]: unknown;
787
- };
788
- content: {
789
- "application/json": components["schemas"]["ErrorResponse"];
790
- };
791
- };
792
850
  };
793
851
  };
794
852
  put?: never;
@@ -799,7 +857,7 @@ interface paths {
799
857
  patch?: never;
800
858
  trace?: never;
801
859
  };
802
- "/v1/procurement/briefs/{id}/matches": {
860
+ "/v1/catalog/{id}/similar": {
803
861
  parameters: {
804
862
  query?: never;
805
863
  header?: never;
@@ -807,14 +865,16 @@ interface paths {
807
865
  cookie?: never;
808
866
  };
809
867
  /**
810
- * Run a sourcing brief against the catalog
811
- * @description Return the catalog coffees that satisfy a saved brief's criteria, each annotated with the deterministic reasons it matched. Requires a member session or a paid (member+) API plan; API keys also need the catalog:read scope.
868
+ * Find catalog coffees similar to a target coffee
869
+ * @description Vector-similarity matches for a target catalog coffee, with deterministic identity gating, supplier-diversity re-ranking, and a canonical/similar split. Requires the bean-matching capability (a member session or a paid API plan).
812
870
  */
813
871
  get: {
814
872
  parameters: {
815
873
  query?: {
816
- page?: number;
874
+ threshold?: string;
817
875
  limit?: number;
876
+ stocked_only?: "true" | "false";
877
+ mode?: "all" | "likely_same" | "similar_profile";
818
878
  };
819
879
  header?: never;
820
880
  path: {
@@ -824,16 +884,16 @@ interface paths {
824
884
  };
825
885
  requestBody?: never;
826
886
  responses: {
827
- /** @description A page of catalog matches for the brief */
887
+ /** @description Target coffee with grouped similarity matches */
828
888
  200: {
829
889
  headers: {
830
890
  [name: string]: unknown;
831
891
  };
832
892
  content: {
833
- "application/json": components["schemas"]["SourcingBriefMatchesResponse"];
893
+ "application/json": components["schemas"]["CatalogSimilarityResponse"];
834
894
  };
835
895
  };
836
- /** @description Invalid pagination parameter */
896
+ /** @description Invalid path id or query parameter */
837
897
  400: {
838
898
  headers: {
839
899
  [name: string]: unknown;
@@ -860,7 +920,7 @@ interface paths {
860
920
  "application/json": components["schemas"]["ErrorResponse"];
861
921
  };
862
922
  };
863
- /** @description No such brief for this principal */
923
+ /** @description Catalog coffee not found */
864
924
  404: {
865
925
  headers: {
866
926
  [name: string]: unknown;
@@ -879,29 +939,288 @@ interface paths {
879
939
  patch?: never;
880
940
  trace?: never;
881
941
  };
882
- }
883
- interface components {
884
- schemas: {
885
- HealthResponse: {
886
- /** @enum {string} */
887
- status: "ok";
888
- /** @enum {string} */
889
- service: "parchment-api";
890
- version: string;
891
- /** Format: date-time */
892
- timestamp: string;
893
- };
894
- DiscoveryResponse: {
895
- /** @enum {string} */
896
- product: "Parchment";
897
- namespace: string;
898
- health: string;
899
- docs: string;
900
- openapi: string;
942
+ "/v1/procurement/briefs": {
943
+ parameters: {
944
+ query?: never;
945
+ header?: never;
946
+ path?: never;
947
+ cookie?: never;
901
948
  };
902
- MeResponse: {
903
- authenticated: boolean;
904
- /** @enum {string} */
949
+ /**
950
+ * List saved sourcing briefs
951
+ * @description List the authenticated principal's active sourcing briefs. Requires a member session or a paid (member+) API plan; API keys also need the catalog:read scope.
952
+ */
953
+ get: {
954
+ parameters: {
955
+ query?: never;
956
+ header?: never;
957
+ path?: never;
958
+ cookie?: never;
959
+ };
960
+ requestBody?: never;
961
+ responses: {
962
+ /** @description The principal's active sourcing briefs */
963
+ 200: {
964
+ headers: {
965
+ [name: string]: unknown;
966
+ };
967
+ content: {
968
+ "application/json": components["schemas"]["SourcingBriefsListResponse"];
969
+ };
970
+ };
971
+ /** @description Authentication required */
972
+ 401: {
973
+ headers: {
974
+ [name: string]: unknown;
975
+ };
976
+ content: {
977
+ "application/json": components["schemas"]["ErrorResponse"];
978
+ };
979
+ };
980
+ /** @description Insufficient entitlement (plan or role) */
981
+ 403: {
982
+ headers: {
983
+ [name: string]: unknown;
984
+ };
985
+ content: {
986
+ "application/json": components["schemas"]["ErrorResponse"];
987
+ };
988
+ };
989
+ };
990
+ };
991
+ put?: never;
992
+ /**
993
+ * Create a sourcing brief
994
+ * @description Create a saved sourcing brief for the authenticated principal. Requires a member session or a paid (member+) API plan; API keys also need the catalog:read scope.
995
+ */
996
+ post: {
997
+ parameters: {
998
+ query?: never;
999
+ header?: never;
1000
+ path?: never;
1001
+ cookie?: never;
1002
+ };
1003
+ requestBody?: {
1004
+ content: {
1005
+ "application/json": components["schemas"]["SourcingBriefCreateRequest"];
1006
+ };
1007
+ };
1008
+ responses: {
1009
+ /** @description The created sourcing brief */
1010
+ 201: {
1011
+ headers: {
1012
+ [name: string]: unknown;
1013
+ };
1014
+ content: {
1015
+ "application/json": components["schemas"]["SourcingBriefResponse"];
1016
+ };
1017
+ };
1018
+ /** @description Invalid request body or unsupported criteria */
1019
+ 400: {
1020
+ headers: {
1021
+ [name: string]: unknown;
1022
+ };
1023
+ content: {
1024
+ "application/json": components["schemas"]["ErrorResponse"];
1025
+ };
1026
+ };
1027
+ /** @description Authentication required */
1028
+ 401: {
1029
+ headers: {
1030
+ [name: string]: unknown;
1031
+ };
1032
+ content: {
1033
+ "application/json": components["schemas"]["ErrorResponse"];
1034
+ };
1035
+ };
1036
+ /** @description Insufficient entitlement (plan or role) */
1037
+ 403: {
1038
+ headers: {
1039
+ [name: string]: unknown;
1040
+ };
1041
+ content: {
1042
+ "application/json": components["schemas"]["ErrorResponse"];
1043
+ };
1044
+ };
1045
+ };
1046
+ };
1047
+ delete?: never;
1048
+ options?: never;
1049
+ head?: never;
1050
+ patch?: never;
1051
+ trace?: never;
1052
+ };
1053
+ "/v1/procurement/briefs/{id}": {
1054
+ parameters: {
1055
+ query?: never;
1056
+ header?: never;
1057
+ path?: never;
1058
+ cookie?: never;
1059
+ };
1060
+ /**
1061
+ * Get a sourcing brief
1062
+ * @description Fetch one of the authenticated principal's sourcing briefs by id. Requires a member session or a paid (member+) API plan; API keys also need the catalog:read scope.
1063
+ */
1064
+ get: {
1065
+ parameters: {
1066
+ query?: never;
1067
+ header?: never;
1068
+ path: {
1069
+ id: string;
1070
+ };
1071
+ cookie?: never;
1072
+ };
1073
+ requestBody?: never;
1074
+ responses: {
1075
+ /** @description The requested sourcing brief */
1076
+ 200: {
1077
+ headers: {
1078
+ [name: string]: unknown;
1079
+ };
1080
+ content: {
1081
+ "application/json": components["schemas"]["SourcingBriefResponse"];
1082
+ };
1083
+ };
1084
+ /** @description Authentication required */
1085
+ 401: {
1086
+ headers: {
1087
+ [name: string]: unknown;
1088
+ };
1089
+ content: {
1090
+ "application/json": components["schemas"]["ErrorResponse"];
1091
+ };
1092
+ };
1093
+ /** @description Insufficient entitlement (plan or role) */
1094
+ 403: {
1095
+ headers: {
1096
+ [name: string]: unknown;
1097
+ };
1098
+ content: {
1099
+ "application/json": components["schemas"]["ErrorResponse"];
1100
+ };
1101
+ };
1102
+ /** @description No such brief for this principal */
1103
+ 404: {
1104
+ headers: {
1105
+ [name: string]: unknown;
1106
+ };
1107
+ content: {
1108
+ "application/json": components["schemas"]["ErrorResponse"];
1109
+ };
1110
+ };
1111
+ };
1112
+ };
1113
+ put?: never;
1114
+ post?: never;
1115
+ delete?: never;
1116
+ options?: never;
1117
+ head?: never;
1118
+ patch?: never;
1119
+ trace?: never;
1120
+ };
1121
+ "/v1/procurement/briefs/{id}/matches": {
1122
+ parameters: {
1123
+ query?: never;
1124
+ header?: never;
1125
+ path?: never;
1126
+ cookie?: never;
1127
+ };
1128
+ /**
1129
+ * Run a sourcing brief against the catalog
1130
+ * @description Return the catalog coffees that satisfy a saved brief's criteria, each annotated with the deterministic reasons it matched. Requires a member session or a paid (member+) API plan; API keys also need the catalog:read scope.
1131
+ */
1132
+ get: {
1133
+ parameters: {
1134
+ query?: {
1135
+ page?: number;
1136
+ limit?: number;
1137
+ };
1138
+ header?: never;
1139
+ path: {
1140
+ id: string;
1141
+ };
1142
+ cookie?: never;
1143
+ };
1144
+ requestBody?: never;
1145
+ responses: {
1146
+ /** @description A page of catalog matches for the brief */
1147
+ 200: {
1148
+ headers: {
1149
+ [name: string]: unknown;
1150
+ };
1151
+ content: {
1152
+ "application/json": components["schemas"]["SourcingBriefMatchesResponse"];
1153
+ };
1154
+ };
1155
+ /** @description Invalid pagination parameter */
1156
+ 400: {
1157
+ headers: {
1158
+ [name: string]: unknown;
1159
+ };
1160
+ content: {
1161
+ "application/json": components["schemas"]["ErrorResponse"];
1162
+ };
1163
+ };
1164
+ /** @description Authentication required */
1165
+ 401: {
1166
+ headers: {
1167
+ [name: string]: unknown;
1168
+ };
1169
+ content: {
1170
+ "application/json": components["schemas"]["ErrorResponse"];
1171
+ };
1172
+ };
1173
+ /** @description Insufficient entitlement (plan or role) */
1174
+ 403: {
1175
+ headers: {
1176
+ [name: string]: unknown;
1177
+ };
1178
+ content: {
1179
+ "application/json": components["schemas"]["ErrorResponse"];
1180
+ };
1181
+ };
1182
+ /** @description No such brief for this principal */
1183
+ 404: {
1184
+ headers: {
1185
+ [name: string]: unknown;
1186
+ };
1187
+ content: {
1188
+ "application/json": components["schemas"]["ErrorResponse"];
1189
+ };
1190
+ };
1191
+ };
1192
+ };
1193
+ put?: never;
1194
+ post?: never;
1195
+ delete?: never;
1196
+ options?: never;
1197
+ head?: never;
1198
+ patch?: never;
1199
+ trace?: never;
1200
+ };
1201
+ }
1202
+ interface components {
1203
+ schemas: {
1204
+ HealthResponse: {
1205
+ /** @enum {string} */
1206
+ status: "ok";
1207
+ /** @enum {string} */
1208
+ service: "parchment-api";
1209
+ version: string;
1210
+ /** Format: date-time */
1211
+ timestamp: string;
1212
+ };
1213
+ DiscoveryResponse: {
1214
+ /** @enum {string} */
1215
+ product: "Parchment";
1216
+ namespace: string;
1217
+ health: string;
1218
+ docs: string;
1219
+ openapi: string;
1220
+ };
1221
+ MeResponse: {
1222
+ authenticated: boolean;
1223
+ /** @enum {string} */
905
1224
  authKind: "anonymous" | "session" | "api-key";
906
1225
  userId: string | null;
907
1226
  appRoles: string[];
@@ -911,885 +1230,1237 @@ interface components {
911
1230
  ppiAccess: boolean;
912
1231
  apiScopes: string[];
913
1232
  };
914
- CatalogAccessResponse: {
915
- visibility: {
916
- isPrivilegedSession: boolean;
917
- publicOnly: boolean;
918
- showWholesale: boolean;
919
- wholesaleOnly: boolean;
1233
+ ApiKeyRecord: {
1234
+ /** Format: uuid */
1235
+ id: string;
1236
+ name: string;
1237
+ /** Format: date-time */
1238
+ createdAt: string | null;
1239
+ /** Format: date-time */
1240
+ lastUsedAt: string | null;
1241
+ isActive: boolean;
1242
+ scopes: string[];
1243
+ };
1244
+ ApiKeyListResponse: {
1245
+ data: components["schemas"]["ApiKeyRecord"][];
1246
+ };
1247
+ ErrorResponse: {
1248
+ error: {
1249
+ code: string;
1250
+ message: string;
1251
+ };
1252
+ };
1253
+ ApiKeyCreateResponse: {
1254
+ /** @description Raw API key. Returned only once; store the secret client-side. */
1255
+ apiKey: string;
1256
+ key: components["schemas"]["ApiKeyRecord"];
1257
+ };
1258
+ ApiKeyMutationResponse: {
1259
+ key: components["schemas"]["ApiKeyRecord"];
1260
+ };
1261
+ CatalogAccessResponse: {
1262
+ visibility: {
1263
+ isPrivilegedSession: boolean;
1264
+ publicOnly: boolean;
1265
+ showWholesale: boolean;
1266
+ wholesaleOnly: boolean;
1267
+ };
1268
+ capabilities: {
1269
+ canViewPublicCatalog: boolean;
1270
+ canViewFullCatalog: boolean;
1271
+ canViewWholesale: boolean;
1272
+ canUseBasicFilters: boolean;
1273
+ canUseAdvancedFilters: boolean;
1274
+ canUseProcessFacets: boolean;
1275
+ canUsePriceScoreRanges: boolean;
1276
+ canUseAdvancedSorts: boolean;
1277
+ canViewPremiumFilterMetadata: boolean;
1278
+ canUseSemanticSearch: boolean;
1279
+ canUseBeanMatching: boolean;
1280
+ canUseSavedSearches: boolean;
1281
+ canExport: boolean;
1282
+ };
1283
+ };
1284
+ CatalogItem: {
1285
+ id: number;
1286
+ name?: string | null;
1287
+ source?: string | null;
1288
+ continent?: string | null;
1289
+ country?: string | null;
1290
+ region?: string | null;
1291
+ processing?: string | null;
1292
+ cultivar_detail?: string | null;
1293
+ type?: string | null;
1294
+ grade?: string | null;
1295
+ appearance?: string | null;
1296
+ score_value?: number | null;
1297
+ cost_lb?: number | null;
1298
+ price_per_lb?: number | null;
1299
+ price_tiers?: unknown;
1300
+ arrival_date?: string | null;
1301
+ stocked_date?: string | null;
1302
+ stocked?: boolean | null;
1303
+ wholesale?: boolean | null;
1304
+ public_coffee?: boolean | null;
1305
+ purveyor_score?: number | null;
1306
+ purveyor_score_confidence?: number | null;
1307
+ purveyor_score_tier?: string | null;
1308
+ purveyor_score_factors?: unknown;
1309
+ purveyor_score_version?: string | null;
1310
+ purveyor_score_updated_at?: string | null;
1311
+ processing_base_method?: string | null;
1312
+ fermentation_type?: string | null;
1313
+ process_additives?: unknown;
1314
+ process_additive_detail?: string | null;
1315
+ fermentation_duration_hours?: number | null;
1316
+ processing_notes?: string | null;
1317
+ processing_disclosure_level?: string | null;
1318
+ processing_confidence?: number | null;
1319
+ processing_evidence_available?: boolean | null;
1320
+ drying_method?: string | null;
1321
+ farm_notes?: string | null;
1322
+ description_short?: string | null;
1323
+ description_long?: string | null;
1324
+ cupping_notes?: string | null;
1325
+ roast_recs?: string | null;
1326
+ lot_size?: string | null;
1327
+ bag_size?: string | null;
1328
+ packaging?: string | null;
1329
+ link?: string | null;
1330
+ last_updated?: string | null;
1331
+ unstocked_date?: string | null;
1332
+ ai_description?: string | null;
1333
+ ai_tasting_notes?: unknown;
1334
+ };
1335
+ CatalogListResponse: {
1336
+ data: components["schemas"]["CatalogItem"][];
1337
+ pagination: {
1338
+ page: number;
1339
+ limit: number;
1340
+ total: number;
1341
+ totalPages: number;
1342
+ hasNext: boolean;
1343
+ hasPrev: boolean;
1344
+ };
1345
+ meta: {
1346
+ /** @enum {string} */
1347
+ resource: "catalog";
1348
+ /** @enum {string} */
1349
+ namespace: "/v1/catalog";
1350
+ /** @enum {string} */
1351
+ version: "v1";
1352
+ auth: {
1353
+ /** @enum {string} */
1354
+ kind: "anonymous" | "session" | "api-key";
1355
+ /** @enum {string|null} */
1356
+ role: "viewer" | "member" | "admin" | null;
1357
+ /** @enum {string|null} */
1358
+ apiPlan: "viewer" | "member" | "enterprise" | null;
1359
+ };
1360
+ access: {
1361
+ publicOnly: boolean;
1362
+ showWholesale: boolean;
1363
+ wholesaleOnly: boolean;
1364
+ rowLimit: number | null;
1365
+ limited: boolean;
1366
+ totalAvailable: number;
1367
+ };
1368
+ /** @description Present only when requested filters/sorts were stripped because the caller lacked the capability. The request still returns 200 with the entitled subset applied. */
1369
+ notices?: {
1370
+ status: 401 | 403;
1371
+ /** @enum {string} */
1372
+ code: "auth_required" | "entitlement_required";
1373
+ message: string;
1374
+ deniedParams: string[];
1375
+ }[];
1376
+ };
1377
+ };
1378
+ CatalogFacetsResponse: {
1379
+ /** @description Compatibility-friendly unique values for dropdown filters. Keys with no values are omitted. */
1380
+ values: {
1381
+ sources?: string[];
1382
+ continents?: string[];
1383
+ countries?: string[];
1384
+ regions?: string[];
1385
+ processing?: string[];
1386
+ cultivar_detail?: string[];
1387
+ type?: string[];
1388
+ grade?: string[];
1389
+ appearance?: string[];
1390
+ arrivalDates?: string[];
1391
+ drying_method?: string[];
1392
+ wholesale?: string[];
1393
+ processing_base_method?: string[];
1394
+ fermentation_type?: string[];
1395
+ process_additives?: string[];
1396
+ processing_disclosure_level?: string[];
1397
+ };
1398
+ /** @description Counted facet values for CLI/agent use. Counts are computed after visibility and entitled query filters are applied. */
1399
+ facets: {
1400
+ sources?: {
1401
+ value: string;
1402
+ count: number;
1403
+ }[];
1404
+ continents?: {
1405
+ value: string;
1406
+ count: number;
1407
+ }[];
1408
+ countries?: {
1409
+ value: string;
1410
+ count: number;
1411
+ }[];
1412
+ regions?: {
1413
+ value: string;
1414
+ count: number;
1415
+ }[];
1416
+ processing?: {
1417
+ value: string;
1418
+ count: number;
1419
+ }[];
1420
+ cultivar_detail?: {
1421
+ value: string;
1422
+ count: number;
1423
+ }[];
1424
+ type?: {
1425
+ value: string;
1426
+ count: number;
1427
+ }[];
1428
+ grade?: {
1429
+ value: string;
1430
+ count: number;
1431
+ }[];
1432
+ appearance?: {
1433
+ value: string;
1434
+ count: number;
1435
+ }[];
1436
+ arrivalDates?: {
1437
+ value: string;
1438
+ count: number;
1439
+ }[];
1440
+ drying_method?: {
1441
+ value: string;
1442
+ count: number;
1443
+ }[];
1444
+ wholesale?: {
1445
+ value: string;
1446
+ count: number;
1447
+ }[];
1448
+ processing_base_method?: {
1449
+ value: string;
1450
+ count: number;
1451
+ }[];
1452
+ fermentation_type?: {
1453
+ value: string;
1454
+ count: number;
1455
+ }[];
1456
+ process_additives?: {
1457
+ value: string;
1458
+ count: number;
1459
+ }[];
1460
+ processing_disclosure_level?: {
1461
+ value: string;
1462
+ count: number;
1463
+ }[];
1464
+ };
1465
+ meta: {
1466
+ /** @enum {string} */
1467
+ resource: "catalog-facets";
1468
+ /** @enum {string} */
1469
+ namespace: "/v1/catalog/facets";
1470
+ /** @enum {string} */
1471
+ version: "v1";
1472
+ auth: {
1473
+ /** @enum {string} */
1474
+ kind: "session" | "api-key";
1475
+ /** @enum {string|null} */
1476
+ role: "viewer" | "member" | "admin" | null;
1477
+ /** @enum {string|null} */
1478
+ apiPlan: "viewer" | "member" | "enterprise" | null;
1479
+ };
1480
+ access: {
1481
+ publicOnly: boolean;
1482
+ showWholesale: boolean;
1483
+ wholesaleOnly: boolean;
1484
+ stocked: boolean | null;
1485
+ premiumMetadata: boolean;
1486
+ };
1487
+ notices?: {
1488
+ status: 401 | 403;
1489
+ /** @enum {string} */
1490
+ code: "auth_required" | "entitlement_required";
1491
+ message: string;
1492
+ deniedParams: string[];
1493
+ }[];
1494
+ };
1495
+ };
1496
+ CatalogOriginPriceStatsResponse: {
1497
+ originPriceStats: {
1498
+ origin: string;
1499
+ median: number;
1500
+ q1: number;
1501
+ q3: number;
1502
+ min: number;
1503
+ max: number;
1504
+ sample_size: number;
1505
+ supplier_count: number;
1506
+ }[];
1507
+ meta: {
1508
+ /** @enum {string} */
1509
+ resource: "catalog-origin-price-stats";
1510
+ /** @enum {string} */
1511
+ namespace: "/v1/catalog/origin-price-stats";
1512
+ /** @enum {string} */
1513
+ version: "v1";
1514
+ auth: {
1515
+ /** @enum {string} */
1516
+ kind: "anonymous" | "session" | "api-key";
1517
+ /** @enum {string|null} */
1518
+ role: "viewer" | "member" | "admin" | null;
1519
+ /** @enum {string|null} */
1520
+ apiPlan: "viewer" | "member" | "enterprise" | null;
1521
+ };
1522
+ access: {
1523
+ publicOnly: boolean;
1524
+ showWholesale: boolean;
1525
+ wholesaleOnly: boolean;
1526
+ /** @enum {string} */
1527
+ scope: "retail" | "wholesale" | "all";
1528
+ totalAvailable: number;
1529
+ };
1530
+ };
1531
+ };
1532
+ CatalogProofCoverageResponse: {
1533
+ meta: {
1534
+ /** @enum {string} */
1535
+ resource: "catalog-proof-coverage";
1536
+ /** @enum {string} */
1537
+ namespace: "/v1/catalog/proof-coverage";
1538
+ /** @enum {string} */
1539
+ version: "v1";
1540
+ auth: {
1541
+ /** @enum {string} */
1542
+ kind: "anonymous" | "session" | "api-key";
1543
+ /** @enum {string|null} */
1544
+ role: "viewer" | "member" | "admin" | null;
1545
+ /** @enum {string|null} */
1546
+ apiPlan: "viewer" | "member" | "enterprise" | null;
1547
+ };
1548
+ access: {
1549
+ publicOnly: boolean;
1550
+ sampled: number;
1551
+ totalAvailable: number;
1552
+ };
1553
+ };
1554
+ coverage: {
1555
+ overall: {
1556
+ label: string;
1557
+ count: number;
1558
+ share: number;
1559
+ }[];
1560
+ families: {
1561
+ [key: string]: {
1562
+ label: string;
1563
+ count: number;
1564
+ share: number;
1565
+ }[];
1566
+ };
1567
+ signals: {
1568
+ [key: string]: number;
1569
+ };
1570
+ top_gaps: {
1571
+ family: string;
1572
+ label: string;
1573
+ count: number;
1574
+ share: number;
1575
+ }[];
1576
+ limitations: string[];
1577
+ };
1578
+ };
1579
+ PriceIndexItem: {
1580
+ date: string;
1581
+ origin: string;
1582
+ process: string | null;
1583
+ grade: string | null;
1584
+ wholesale: boolean;
1585
+ price: {
1586
+ min: number | null;
1587
+ max: number | null;
1588
+ avg: number | null;
1589
+ median: number | null;
1590
+ p25: number | null;
1591
+ p75: number | null;
1592
+ stdev: number | null;
1593
+ };
1594
+ sample: {
1595
+ suppliers: number;
1596
+ listings: number;
1597
+ aggregationTier: number | null;
1598
+ };
1599
+ provenance: {
1600
+ synthetic: boolean;
1601
+ };
1602
+ };
1603
+ PriceIndexResponse: {
1604
+ data: components["schemas"]["PriceIndexItem"][];
1605
+ pagination: {
1606
+ page: number;
1607
+ limit: number;
1608
+ total: number;
1609
+ totalPages: number;
1610
+ hasNext: boolean;
1611
+ hasPrev: boolean;
1612
+ };
1613
+ meta: {
1614
+ /** @enum {string} */
1615
+ resource: "price-index";
1616
+ /** @enum {string} */
1617
+ namespace: "/v1/price-index";
1618
+ /** @enum {string} */
1619
+ version: "v1";
1620
+ auth: {
1621
+ /** @enum {string} */
1622
+ kind: "api-key";
1623
+ /** @enum {string|null} */
1624
+ apiPlan: "viewer" | "member" | "enterprise" | null;
1625
+ /** @enum {boolean} */
1626
+ ppiAccess: true;
1627
+ };
1628
+ filters: {
1629
+ origin: string | null;
1630
+ process: string | null;
1631
+ grade: string | null;
1632
+ from: string | null;
1633
+ to: string | null;
1634
+ wholesale: boolean | null;
1635
+ };
1636
+ access: {
1637
+ rowLimit: number | null;
1638
+ limited: boolean;
1639
+ totalAvailable: number;
1640
+ };
1641
+ source: {
1642
+ /** @enum {string} */
1643
+ table: "price_index_snapshots";
1644
+ /** @enum {boolean} */
1645
+ aggregateOnly: true;
1646
+ };
1647
+ };
1648
+ };
1649
+ CatalogSimilarityTarget: {
1650
+ id: number;
1651
+ name: string;
1652
+ source: string | null;
1653
+ origin: string | null;
1654
+ country: string | null;
1655
+ continent: string | null;
1656
+ processing: string | null;
1657
+ processing_base_method: string | null;
1658
+ fermentation_type: string | null;
1659
+ drying_method: string | null;
1660
+ stocked: boolean | null;
1661
+ arrival_date: string | null;
1662
+ stocked_date: string | null;
1663
+ price_per_lb: number | null;
1664
+ price_tiers?: unknown;
1665
+ cost_lb: number | null;
1666
+ pricing: {
1667
+ price_per_lb: number | null;
1668
+ price_tiers?: unknown;
1669
+ cost_lb: number | null;
1670
+ /** @enum {number} */
1671
+ baseline_quantity_lbs: 1;
1672
+ baseline_price_per_lb: number | null;
1673
+ /** @enum {string|null} */
1674
+ baseline_source: "price_per_lb" | "price_tiers" | "cost_lb" | null;
1675
+ };
1676
+ proof: {
1677
+ /** @enum {string} */
1678
+ version: "proof-summary-v1";
1679
+ overall: {
1680
+ /** @enum {string} */
1681
+ label: "strong" | "partial" | "limited" | "not_available";
1682
+ families_with_signals: number;
1683
+ };
1684
+ families: {
1685
+ process: {
1686
+ label: string;
1687
+ confidence: number | null;
1688
+ signals: string[];
1689
+ message: string;
1690
+ };
1691
+ provenance: {
1692
+ label: string;
1693
+ confidence: number | null;
1694
+ signals: string[];
1695
+ message: string;
1696
+ };
1697
+ freshness: {
1698
+ label: string;
1699
+ confidence: number | null;
1700
+ signals: string[];
1701
+ message: string;
1702
+ };
1703
+ pricing: {
1704
+ label: string;
1705
+ confidence: number | null;
1706
+ signals: string[];
1707
+ message: string;
1708
+ };
1709
+ };
1710
+ limitations: string[];
1711
+ };
1712
+ };
1713
+ CatalogSimilarityMatch: {
1714
+ coffee: {
1715
+ id: number;
1716
+ name: string;
1717
+ source: string | null;
1718
+ origin: string | null;
1719
+ country: string | null;
1720
+ continent: string | null;
1721
+ processing: string | null;
1722
+ processing_base_method: string | null;
1723
+ fermentation_type: string | null;
1724
+ drying_method: string | null;
1725
+ stocked: boolean | null;
1726
+ arrival_date: string | null;
1727
+ stocked_date: string | null;
1728
+ proof: {
1729
+ /** @enum {string} */
1730
+ version: "proof-summary-v1";
1731
+ overall: {
1732
+ /** @enum {string} */
1733
+ label: "strong" | "partial" | "limited" | "not_available";
1734
+ families_with_signals: number;
1735
+ };
1736
+ families: {
1737
+ process: {
1738
+ label: string;
1739
+ confidence: number | null;
1740
+ signals: string[];
1741
+ message: string;
1742
+ };
1743
+ provenance: {
1744
+ label: string;
1745
+ confidence: number | null;
1746
+ signals: string[];
1747
+ message: string;
1748
+ };
1749
+ freshness: {
1750
+ label: string;
1751
+ confidence: number | null;
1752
+ signals: string[];
1753
+ message: string;
1754
+ };
1755
+ pricing: {
1756
+ label: string;
1757
+ confidence: number | null;
1758
+ signals: string[];
1759
+ message: string;
1760
+ };
1761
+ };
1762
+ limitations: string[];
1763
+ };
1764
+ };
1765
+ pricing: {
1766
+ price_per_lb: number | null;
1767
+ price_tiers?: unknown;
1768
+ cost_lb: number | null;
1769
+ /** @enum {number} */
1770
+ baseline_quantity_lbs: 1;
1771
+ baseline_price_per_lb: number | null;
1772
+ /** @enum {string|null} */
1773
+ baseline_source: "price_per_lb" | "price_tiers" | "cost_lb" | null;
1774
+ };
1775
+ price_delta_1lb: {
1776
+ amount: number | null;
1777
+ percent: number | null;
1778
+ /** @enum {string} */
1779
+ currency: "USD";
1780
+ };
1781
+ score: {
1782
+ average: number;
1783
+ dimensions: {
1784
+ origin: number | null;
1785
+ processing: number | null;
1786
+ tasting: number | null;
1787
+ };
1788
+ chunk_matches: number;
1789
+ };
1790
+ match: {
1791
+ /** @enum {string} */
1792
+ category: "likely_same" | "similar_profile";
1793
+ classification: {
1794
+ /** @enum {string} */
1795
+ kind: "canonical_candidate" | "similar_recommendation";
1796
+ /** @enum {string} */
1797
+ identity_eligibility: "eligible" | "blocked" | "insufficient_evidence";
1798
+ /** @enum {string} */
1799
+ confidence: "high_beta" | "medium_beta" | "low_beta";
1800
+ blockers: {
1801
+ code: string;
1802
+ /** @enum {string} */
1803
+ severity: "hard" | "soft";
1804
+ target_value: string | null;
1805
+ candidate_value: string | null;
1806
+ }[];
1807
+ evidence: string[];
1808
+ };
1809
+ /** @enum {string} */
1810
+ confidence: "high_beta" | "medium_beta" | "low_beta";
1811
+ /** @enum {boolean} */
1812
+ beta: true;
1813
+ language: string;
1814
+ same_supplier: boolean;
920
1815
  };
921
- capabilities: {
922
- canViewPublicCatalog: boolean;
923
- canViewFullCatalog: boolean;
924
- canViewWholesale: boolean;
925
- canUseBasicFilters: boolean;
926
- canUseAdvancedFilters: boolean;
927
- canUseProcessFacets: boolean;
928
- canUsePriceScoreRanges: boolean;
929
- canUseAdvancedSorts: boolean;
930
- canViewPremiumFilterMetadata: boolean;
931
- canUseSemanticSearch: boolean;
932
- canUseBeanMatching: boolean;
933
- canUseSavedSearches: boolean;
934
- canExport: boolean;
1816
+ explanation: {
1817
+ summary: string;
1818
+ signals: string[];
935
1819
  };
936
- };
937
- ErrorResponse: {
938
- error: {
939
- code: string;
940
- message: string;
1820
+ compatibility: {
1821
+ cost_lb: number | null;
941
1822
  };
942
1823
  };
943
- CatalogItem: {
944
- id: number;
945
- name?: string | null;
946
- source?: string | null;
947
- continent?: string | null;
948
- country?: string | null;
949
- region?: string | null;
950
- processing?: string | null;
951
- cultivar_detail?: string | null;
952
- type?: string | null;
953
- grade?: string | null;
954
- appearance?: string | null;
955
- score_value?: number | null;
956
- cost_lb?: number | null;
957
- price_per_lb?: number | null;
958
- price_tiers?: unknown;
959
- arrival_date?: string | null;
960
- stocked_date?: string | null;
961
- stocked?: boolean | null;
962
- wholesale?: boolean | null;
963
- public_coffee?: boolean | null;
964
- purveyor_score?: number | null;
965
- purveyor_score_confidence?: number | null;
966
- purveyor_score_tier?: string | null;
967
- purveyor_score_factors?: unknown;
968
- purveyor_score_version?: string | null;
969
- purveyor_score_updated_at?: string | null;
970
- processing_base_method?: string | null;
971
- fermentation_type?: string | null;
972
- process_additives?: unknown;
973
- process_additive_detail?: string | null;
974
- fermentation_duration_hours?: number | null;
975
- processing_notes?: string | null;
976
- processing_disclosure_level?: string | null;
977
- processing_confidence?: number | null;
978
- processing_evidence_available?: boolean | null;
979
- drying_method?: string | null;
980
- farm_notes?: string | null;
981
- description_short?: string | null;
982
- description_long?: string | null;
983
- cupping_notes?: string | null;
984
- roast_recs?: string | null;
985
- lot_size?: string | null;
986
- bag_size?: string | null;
987
- packaging?: string | null;
988
- link?: string | null;
989
- last_updated?: string | null;
990
- unstocked_date?: string | null;
991
- ai_description?: string | null;
992
- ai_tasting_notes?: unknown;
993
- };
994
- CatalogListResponse: {
995
- data: components["schemas"]["CatalogItem"][];
996
- pagination: {
997
- page: number;
998
- limit: number;
999
- total: number;
1000
- totalPages: number;
1001
- hasNext: boolean;
1002
- hasPrev: boolean;
1824
+ CatalogSimilarityResponse: {
1825
+ data: {
1826
+ target: components["schemas"]["CatalogSimilarityTarget"];
1827
+ groups: {
1828
+ canonical_candidates: components["schemas"]["CatalogSimilarityMatch"][];
1829
+ similar_recommendations: components["schemas"]["CatalogSimilarityMatch"][];
1830
+ };
1831
+ matches: components["schemas"]["CatalogSimilarityMatch"][];
1003
1832
  };
1004
1833
  meta: {
1005
1834
  /** @enum {string} */
1006
- resource: "catalog";
1835
+ resource: "catalog-similarity";
1007
1836
  /** @enum {string} */
1008
- namespace: "/v1/catalog";
1837
+ namespace: "/v1/catalog/{id}/similar";
1009
1838
  /** @enum {string} */
1010
1839
  version: "v1";
1840
+ /** @enum {string} */
1841
+ status: "beta";
1011
1842
  auth: {
1012
1843
  /** @enum {string} */
1013
- kind: "anonymous" | "session" | "api-key";
1844
+ kind: "session" | "api-key";
1014
1845
  /** @enum {string|null} */
1015
1846
  role: "viewer" | "member" | "admin" | null;
1016
1847
  /** @enum {string|null} */
1017
1848
  apiPlan: "viewer" | "member" | "enterprise" | null;
1018
1849
  };
1019
1850
  access: {
1020
- publicOnly: boolean;
1021
- showWholesale: boolean;
1022
- wholesaleOnly: boolean;
1023
- rowLimit: number | null;
1024
- limited: boolean;
1025
- totalAvailable: number;
1851
+ /** @enum {string} */
1852
+ requiredCapability: "canUseBeanMatching";
1853
+ /** @enum {boolean} */
1854
+ canUseBeanMatching: true;
1026
1855
  };
1027
- /** @description Present only when requested filters/sorts were stripped because the caller lacked the capability. The request still returns 200 with the entitled subset applied. */
1028
- notices?: {
1029
- status: 401 | 403;
1856
+ query: {
1857
+ threshold: number;
1858
+ limit: number;
1859
+ stockedOnly: boolean;
1030
1860
  /** @enum {string} */
1031
- code: "auth_required" | "entitlement_required";
1032
- message: string;
1033
- deniedParams: string[];
1034
- }[];
1861
+ mode: "all" | "likely_same" | "similar_profile";
1862
+ };
1863
+ copy: {
1864
+ confidence: string;
1865
+ };
1866
+ /** @enum {string} */
1867
+ classification_version: "canonical-match-v1";
1868
+ /** @enum {string} */
1869
+ query_strategy: "bounded-vector-candidates-v1" | "canonical-vector-aggregated-v2" | "legacy-vector-aggregated-v1";
1035
1870
  };
1036
1871
  };
1037
- CatalogFacetsResponse: {
1038
- /** @description Compatibility-friendly unique values for dropdown filters. Keys with no values are omitted. */
1039
- values: {
1040
- sources?: string[];
1041
- continents?: string[];
1042
- countries?: string[];
1043
- regions?: string[];
1044
- processing?: string[];
1045
- cultivar_detail?: string[];
1046
- type?: string[];
1047
- grade?: string[];
1048
- appearance?: string[];
1049
- arrivalDates?: string[];
1050
- drying_method?: string[];
1051
- wholesale?: string[];
1052
- processing_base_method?: string[];
1053
- fermentation_type?: string[];
1054
- process_additives?: string[];
1055
- processing_disclosure_level?: string[];
1056
- };
1057
- /** @description Counted facet values for CLI/agent use. Counts are computed after visibility and entitled query filters are applied. */
1058
- facets: {
1059
- sources?: {
1060
- value: string;
1061
- count: number;
1062
- }[];
1063
- continents?: {
1064
- value: string;
1065
- count: number;
1066
- }[];
1067
- countries?: {
1068
- value: string;
1069
- count: number;
1070
- }[];
1071
- regions?: {
1072
- value: string;
1073
- count: number;
1074
- }[];
1075
- processing?: {
1076
- value: string;
1077
- count: number;
1078
- }[];
1079
- cultivar_detail?: {
1080
- value: string;
1081
- count: number;
1082
- }[];
1083
- type?: {
1084
- value: string;
1085
- count: number;
1086
- }[];
1087
- grade?: {
1088
- value: string;
1089
- count: number;
1090
- }[];
1091
- appearance?: {
1092
- value: string;
1093
- count: number;
1094
- }[];
1095
- arrivalDates?: {
1096
- value: string;
1097
- count: number;
1098
- }[];
1099
- drying_method?: {
1100
- value: string;
1101
- count: number;
1102
- }[];
1103
- wholesale?: {
1104
- value: string;
1105
- count: number;
1106
- }[];
1107
- processing_base_method?: {
1108
- value: string;
1109
- count: number;
1110
- }[];
1111
- fermentation_type?: {
1112
- value: string;
1113
- count: number;
1114
- }[];
1115
- process_additives?: {
1116
- value: string;
1117
- count: number;
1118
- }[];
1119
- processing_disclosure_level?: {
1120
- value: string;
1121
- count: number;
1122
- }[];
1123
- };
1872
+ SourcingBriefCriteria: {
1873
+ /** @enum {number} */
1874
+ version?: 1;
1875
+ country?: string;
1876
+ region?: string;
1877
+ processing?: string;
1878
+ processing_base_method?: string;
1879
+ max_price_per_lb?: number;
1880
+ stocked_only?: boolean;
1881
+ wholesale_only?: boolean;
1882
+ stocked_days?: number;
1883
+ };
1884
+ SourcingBriefResource: {
1885
+ id: string;
1886
+ name: string;
1887
+ criteria: components["schemas"]["SourcingBriefCriteria"] & Record<string, never>;
1888
+ /** @enum {string} */
1889
+ cadence: "manual";
1890
+ isActive: boolean;
1891
+ lastRunAt: string | null;
1892
+ createdAt: string;
1893
+ updatedAt: string;
1894
+ };
1895
+ SourcingBriefsListResponse: {
1896
+ data: components["schemas"]["SourcingBriefResource"][];
1124
1897
  meta: {
1125
1898
  /** @enum {string} */
1126
- resource: "catalog-facets";
1899
+ resource: "procurement-briefs";
1127
1900
  /** @enum {string} */
1128
- namespace: "/v1/catalog/facets";
1901
+ namespace: "/v1/procurement/briefs";
1129
1902
  /** @enum {string} */
1130
1903
  version: "v1";
1131
1904
  auth: {
1132
1905
  /** @enum {string} */
1133
1906
  kind: "session" | "api-key";
1134
1907
  /** @enum {string|null} */
1135
- role: "viewer" | "member" | "admin" | null;
1908
+ role: "admin" | "member" | "viewer" | null;
1136
1909
  /** @enum {string|null} */
1137
1910
  apiPlan: "viewer" | "member" | "enterprise" | null;
1138
1911
  };
1139
- access: {
1140
- publicOnly: boolean;
1141
- showWholesale: boolean;
1142
- wholesaleOnly: boolean;
1143
- stocked: boolean | null;
1144
- premiumMetadata: boolean;
1145
- };
1146
- notices?: {
1147
- status: 401 | 403;
1148
- /** @enum {string} */
1149
- code: "auth_required" | "entitlement_required";
1150
- message: string;
1151
- deniedParams: string[];
1152
- }[];
1153
1912
  };
1154
1913
  };
1155
- CatalogOriginPriceStatsResponse: {
1156
- originPriceStats: {
1157
- origin: string;
1158
- median: number;
1159
- q1: number;
1160
- q3: number;
1161
- min: number;
1162
- max: number;
1163
- sample_size: number;
1164
- supplier_count: number;
1165
- }[];
1914
+ SourcingBriefResponse: {
1915
+ data: components["schemas"]["SourcingBriefResource"];
1166
1916
  meta: {
1167
1917
  /** @enum {string} */
1168
- resource: "catalog-origin-price-stats";
1918
+ resource: "procurement-brief";
1169
1919
  /** @enum {string} */
1170
- namespace: "/v1/catalog/origin-price-stats";
1920
+ namespace: "/v1/procurement/briefs" | "/v1/procurement/briefs/:id";
1171
1921
  /** @enum {string} */
1172
1922
  version: "v1";
1173
1923
  auth: {
1174
1924
  /** @enum {string} */
1175
- kind: "anonymous" | "session" | "api-key";
1925
+ kind: "session" | "api-key";
1176
1926
  /** @enum {string|null} */
1177
- role: "viewer" | "member" | "admin" | null;
1927
+ role: "admin" | "member" | "viewer" | null;
1178
1928
  /** @enum {string|null} */
1179
1929
  apiPlan: "viewer" | "member" | "enterprise" | null;
1180
1930
  };
1181
- access: {
1182
- publicOnly: boolean;
1183
- showWholesale: boolean;
1184
- wholesaleOnly: boolean;
1185
- /** @enum {string} */
1186
- scope: "retail" | "wholesale" | "all";
1187
- totalAvailable: number;
1188
- };
1189
1931
  };
1190
1932
  };
1191
- CatalogProofCoverageResponse: {
1933
+ SourcingBriefCreateRequest: {
1934
+ /** @description Human label, 1-120 chars. */
1935
+ name: string;
1936
+ criteria: components["schemas"]["SourcingBriefCriteria"] & unknown;
1937
+ /** @enum {string} */
1938
+ cadence?: "manual";
1939
+ };
1940
+ SourcingBriefMatch: {
1941
+ id: number;
1942
+ name?: string | null;
1943
+ source?: string | null;
1944
+ continent?: string | null;
1945
+ country?: string | null;
1946
+ region?: string | null;
1947
+ processing?: string | null;
1948
+ processing_base_method?: string | null;
1949
+ fermentation_type?: string | null;
1950
+ drying_method?: string | null;
1951
+ cultivar_detail?: string | null;
1952
+ type?: string | null;
1953
+ grade?: string | null;
1954
+ appearance?: string | null;
1955
+ score_value?: number | null;
1956
+ purveyor_score?: number | null;
1957
+ cost_lb?: number | null;
1958
+ price_per_lb?: number | null;
1959
+ price_tiers?: unknown;
1960
+ arrival_date?: string | null;
1961
+ stocked_date?: string | null;
1962
+ stocked?: boolean | null;
1963
+ wholesale?: boolean | null;
1964
+ public_coffee?: boolean | null;
1965
+ matchReasons: string[];
1966
+ };
1967
+ SourcingBriefMatchesResponse: {
1968
+ data: components["schemas"]["SourcingBriefMatch"][];
1969
+ pagination: {
1970
+ page: number;
1971
+ limit: number;
1972
+ total: number;
1973
+ totalPages: number;
1974
+ hasNext: boolean;
1975
+ hasPrev: boolean;
1976
+ };
1192
1977
  meta: {
1193
1978
  /** @enum {string} */
1194
- resource: "catalog-proof-coverage";
1979
+ resource: "procurement-brief-matches";
1195
1980
  /** @enum {string} */
1196
- namespace: "/v1/catalog/proof-coverage";
1981
+ namespace: "/v1/procurement/briefs/:id/matches";
1197
1982
  /** @enum {string} */
1198
1983
  version: "v1";
1984
+ generatedAt: string;
1199
1985
  auth: {
1200
1986
  /** @enum {string} */
1201
- kind: "anonymous" | "session" | "api-key";
1987
+ kind: "session" | "api-key";
1202
1988
  /** @enum {string|null} */
1203
- role: "viewer" | "member" | "admin" | null;
1989
+ role: "admin" | "member" | "viewer" | null;
1204
1990
  /** @enum {string|null} */
1205
1991
  apiPlan: "viewer" | "member" | "enterprise" | null;
1206
1992
  };
1207
- access: {
1208
- publicOnly: boolean;
1209
- sampled: number;
1210
- totalAvailable: number;
1211
- };
1993
+ brief: components["schemas"]["SourcingBriefResource"];
1994
+ criteria: components["schemas"]["SourcingBriefCriteria"] & Record<string, never>;
1995
+ limitations: string[];
1212
1996
  };
1213
- coverage: {
1214
- overall: {
1215
- label: string;
1216
- count: number;
1217
- share: number;
1218
- }[];
1219
- families: {
1220
- [key: string]: {
1221
- label: string;
1222
- count: number;
1223
- share: number;
1224
- }[];
1997
+ };
1998
+ };
1999
+ responses: never;
2000
+ parameters: never;
2001
+ requestBodies: never;
2002
+ headers: never;
2003
+ pathItems: never;
2004
+ }
2005
+
2006
+ interface ParchmentClientOptions {
2007
+ /** Base URL of the Parchment API, e.g. https://api.purveyors.io */
2008
+ baseUrl: string;
2009
+ /**
2010
+ * Optional bearer token (a Supabase JWT or, later, an API key). Sent as
2011
+ * `Authorization: Bearer <token>`. Auth is resolved server-side against the
2012
+ * unified principal model; the SDK only forwards the credential.
2013
+ */
2014
+ token?: string;
2015
+ /** Override the fetch implementation (useful for tests or custom runtimes). */
2016
+ fetch?: ClientOptions["fetch"];
2017
+ }
2018
+ /** Query parameters for {@link ParchmentClient.catalog.list}. */
2019
+ type CatalogListQuery = NonNullable<paths["/v1/catalog"]["get"]["parameters"]["query"]>;
2020
+ /** Query parameters for {@link ParchmentClient.catalog.facets}. */
2021
+ type CatalogFacetsQuery = NonNullable<paths["/v1/catalog/facets"]["get"]["parameters"]["query"]>;
2022
+ /**
2023
+ * Optional headers for {@link ParchmentClient.catalog.list}, notably the
2024
+ * RFC 7240 `Prefer: handling=lenient|strict` override (PADR-0013 §7). Sending
2025
+ * `handling=lenient` opts a strict caller (API key or bearer-session JWT) back
2026
+ * into strip-with-notice degradation instead of a 401/403 hard-deny.
2027
+ */
2028
+ type CatalogListHeaders = NonNullable<paths["/v1/catalog"]["get"]["parameters"]["header"]>;
2029
+ /** Optional headers for {@link ParchmentClient.catalog.facets}; see {@link CatalogListHeaders}. */
2030
+ type CatalogFacetsHeaders = NonNullable<paths["/v1/catalog/facets"]["get"]["parameters"]["header"]>;
2031
+ /** Query parameters for {@link ParchmentClient.catalog.originPriceStats}. */
2032
+ type CatalogOriginPriceStatsQuery = NonNullable<paths["/v1/catalog/origin-price-stats"]["get"]["parameters"]["query"]>;
2033
+ /** Query parameters for {@link ParchmentClient.catalog.similar}. */
2034
+ type CatalogSimilarQuery = NonNullable<paths["/v1/catalog/{id}/similar"]["get"]["parameters"]["query"]>;
2035
+ /** Query parameters for {@link ParchmentClient.priceIndex.list}. */
2036
+ type PriceIndexQuery = NonNullable<paths["/v1/price-index"]["get"]["parameters"]["query"]>;
2037
+ /** Query parameters for {@link ParchmentClient.procurement.briefs.matches}. */
2038
+ type BriefMatchesQuery = NonNullable<paths["/v1/procurement/briefs/{id}/matches"]["get"]["parameters"]["query"]>;
2039
+ /** Request body for {@link ParchmentClient.procurement.briefs.create}. */
2040
+ type SourcingBriefCreateRequest = components["schemas"]["SourcingBriefCreateRequest"];
2041
+ /** Request body for {@link ParchmentClient.apiKeys.create}. */
2042
+ type ApiKeyCreateRequest = NonNullable<paths["/v1/api-keys"]["post"]["requestBody"]>["content"]["application/json"];
2043
+ /**
2044
+ * Create a typed Parchment API client.
2045
+ *
2046
+ * The generated core (openapi-fetch over the generated `paths` types) is the
2047
+ * contract truth; the named helpers below are the hand-maintained ergonomic
2048
+ * layer and grow as endpoints land. `raw` always exposes the underlying typed
2049
+ * client for direct path access to anything not yet wrapped.
2050
+ */
2051
+ declare function createParchmentClient(options: ParchmentClientOptions): {
2052
+ /** The underlying typed openapi-fetch client for direct path access. */
2053
+ raw: openapi_fetch.Client<paths, `${string}/${string}`>;
2054
+ /** Liveness and service identity. */
2055
+ health: () => Promise<openapi_fetch.FetchResponse<{
2056
+ parameters: {
2057
+ query?: never;
2058
+ header?: never;
2059
+ path?: never;
2060
+ cookie?: never;
2061
+ };
2062
+ requestBody?: never;
2063
+ responses: {
2064
+ 200: {
2065
+ headers: {
2066
+ [name: string]: unknown;
1225
2067
  };
1226
- signals: {
1227
- [key: string]: number;
2068
+ content: {
2069
+ "application/json": components["schemas"]["HealthResponse"];
1228
2070
  };
1229
- top_gaps: {
1230
- family: string;
1231
- label: string;
1232
- count: number;
1233
- share: number;
1234
- }[];
1235
- limitations: string[];
1236
2071
  };
1237
2072
  };
1238
- PriceIndexItem: {
1239
- date: string;
1240
- origin: string;
1241
- process: string | null;
1242
- grade: string | null;
1243
- wholesale: boolean;
1244
- price: {
1245
- min: number | null;
1246
- max: number | null;
1247
- avg: number | null;
1248
- median: number | null;
1249
- p25: number | null;
1250
- p75: number | null;
1251
- stdev: number | null;
2073
+ }, openapi_fetch.FetchOptions<{
2074
+ parameters: {
2075
+ query?: never;
2076
+ header?: never;
2077
+ path?: never;
2078
+ cookie?: never;
2079
+ };
2080
+ requestBody?: never;
2081
+ responses: {
2082
+ 200: {
2083
+ headers: {
2084
+ [name: string]: unknown;
2085
+ };
2086
+ content: {
2087
+ "application/json": components["schemas"]["HealthResponse"];
2088
+ };
1252
2089
  };
1253
- sample: {
1254
- suppliers: number;
1255
- listings: number;
1256
- aggregationTier: number | null;
2090
+ };
2091
+ }> | undefined, `${string}/${string}`>>;
2092
+ /** Resolved principal and entitlements for the caller. */
2093
+ me: () => Promise<openapi_fetch.FetchResponse<{
2094
+ parameters: {
2095
+ query?: never;
2096
+ header?: never;
2097
+ path?: never;
2098
+ cookie?: never;
2099
+ };
2100
+ requestBody?: never;
2101
+ responses: {
2102
+ 200: {
2103
+ headers: {
2104
+ [name: string]: unknown;
2105
+ };
2106
+ content: {
2107
+ "application/json": components["schemas"]["MeResponse"];
2108
+ };
1257
2109
  };
1258
- provenance: {
1259
- synthetic: boolean;
2110
+ };
2111
+ }, openapi_fetch.FetchOptions<{
2112
+ parameters: {
2113
+ query?: never;
2114
+ header?: never;
2115
+ path?: never;
2116
+ cookie?: never;
2117
+ };
2118
+ requestBody?: never;
2119
+ responses: {
2120
+ 200: {
2121
+ headers: {
2122
+ [name: string]: unknown;
2123
+ };
2124
+ content: {
2125
+ "application/json": components["schemas"]["MeResponse"];
2126
+ };
1260
2127
  };
1261
2128
  };
1262
- PriceIndexResponse: {
1263
- data: components["schemas"]["PriceIndexItem"][];
1264
- pagination: {
1265
- page: number;
1266
- limit: number;
1267
- total: number;
1268
- totalPages: number;
1269
- hasNext: boolean;
1270
- hasPrev: boolean;
2129
+ }> | undefined, `${string}/${string}`>>;
2130
+ apiKeys: {
2131
+ /** List API keys owned by the authenticated session user. */
2132
+ list: () => Promise<openapi_fetch.FetchResponse<{
2133
+ parameters: {
2134
+ query?: never;
2135
+ header?: never;
2136
+ path?: never;
2137
+ cookie?: never;
1271
2138
  };
1272
- meta: {
1273
- /** @enum {string} */
1274
- resource: "price-index";
1275
- /** @enum {string} */
1276
- namespace: "/v1/price-index";
1277
- /** @enum {string} */
1278
- version: "v1";
1279
- auth: {
1280
- /** @enum {string} */
1281
- kind: "api-key";
1282
- /** @enum {string|null} */
1283
- apiPlan: "viewer" | "member" | "enterprise" | null;
1284
- /** @enum {boolean} */
1285
- ppiAccess: true;
2139
+ requestBody?: never;
2140
+ responses: {
2141
+ 200: {
2142
+ headers: {
2143
+ [name: string]: unknown;
2144
+ };
2145
+ content: {
2146
+ "application/json": components["schemas"]["ApiKeyListResponse"];
2147
+ };
1286
2148
  };
1287
- filters: {
1288
- origin: string | null;
1289
- process: string | null;
1290
- grade: string | null;
1291
- from: string | null;
1292
- to: string | null;
1293
- wholesale: boolean | null;
2149
+ 400: {
2150
+ headers: {
2151
+ [name: string]: unknown;
2152
+ };
2153
+ content: {
2154
+ "application/json": components["schemas"]["ErrorResponse"];
2155
+ };
1294
2156
  };
1295
- access: {
1296
- rowLimit: number | null;
1297
- limited: boolean;
1298
- totalAvailable: number;
2157
+ 401: {
2158
+ headers: {
2159
+ [name: string]: unknown;
2160
+ };
2161
+ content: {
2162
+ "application/json": components["schemas"]["ErrorResponse"];
2163
+ };
1299
2164
  };
1300
- source: {
1301
- /** @enum {string} */
1302
- table: "price_index_snapshots";
1303
- /** @enum {boolean} */
1304
- aggregateOnly: true;
2165
+ 403: {
2166
+ headers: {
2167
+ [name: string]: unknown;
2168
+ };
2169
+ content: {
2170
+ "application/json": components["schemas"]["ErrorResponse"];
2171
+ };
2172
+ };
2173
+ 404: {
2174
+ headers: {
2175
+ [name: string]: unknown;
2176
+ };
2177
+ content: {
2178
+ "application/json": components["schemas"]["ErrorResponse"];
2179
+ };
2180
+ };
2181
+ 503: {
2182
+ headers: {
2183
+ [name: string]: unknown;
2184
+ };
2185
+ content: {
2186
+ "application/json": components["schemas"]["ErrorResponse"];
2187
+ };
1305
2188
  };
1306
2189
  };
1307
- };
1308
- CatalogSimilarityTarget: {
1309
- id: number;
1310
- name: string;
1311
- source: string | null;
1312
- origin: string | null;
1313
- country: string | null;
1314
- continent: string | null;
1315
- processing: string | null;
1316
- processing_base_method: string | null;
1317
- fermentation_type: string | null;
1318
- drying_method: string | null;
1319
- stocked: boolean | null;
1320
- arrival_date: string | null;
1321
- stocked_date: string | null;
1322
- price_per_lb: number | null;
1323
- price_tiers?: unknown;
1324
- cost_lb: number | null;
1325
- pricing: {
1326
- price_per_lb: number | null;
1327
- price_tiers?: unknown;
1328
- cost_lb: number | null;
1329
- /** @enum {number} */
1330
- baseline_quantity_lbs: 1;
1331
- baseline_price_per_lb: number | null;
1332
- /** @enum {string|null} */
1333
- baseline_source: "price_per_lb" | "price_tiers" | "cost_lb" | null;
2190
+ }, openapi_fetch.FetchOptions<{
2191
+ parameters: {
2192
+ query?: never;
2193
+ header?: never;
2194
+ path?: never;
2195
+ cookie?: never;
1334
2196
  };
1335
- proof: {
1336
- /** @enum {string} */
1337
- version: "proof-summary-v1";
1338
- overall: {
1339
- /** @enum {string} */
1340
- label: "strong" | "partial" | "limited" | "not_available";
1341
- families_with_signals: number;
2197
+ requestBody?: never;
2198
+ responses: {
2199
+ 200: {
2200
+ headers: {
2201
+ [name: string]: unknown;
2202
+ };
2203
+ content: {
2204
+ "application/json": components["schemas"]["ApiKeyListResponse"];
2205
+ };
1342
2206
  };
1343
- families: {
1344
- process: {
1345
- label: string;
1346
- confidence: number | null;
1347
- signals: string[];
1348
- message: string;
2207
+ 400: {
2208
+ headers: {
2209
+ [name: string]: unknown;
1349
2210
  };
1350
- provenance: {
1351
- label: string;
1352
- confidence: number | null;
1353
- signals: string[];
1354
- message: string;
2211
+ content: {
2212
+ "application/json": components["schemas"]["ErrorResponse"];
1355
2213
  };
1356
- freshness: {
1357
- label: string;
1358
- confidence: number | null;
1359
- signals: string[];
1360
- message: string;
2214
+ };
2215
+ 401: {
2216
+ headers: {
2217
+ [name: string]: unknown;
1361
2218
  };
1362
- pricing: {
1363
- label: string;
1364
- confidence: number | null;
1365
- signals: string[];
1366
- message: string;
2219
+ content: {
2220
+ "application/json": components["schemas"]["ErrorResponse"];
1367
2221
  };
1368
2222
  };
1369
- limitations: string[];
1370
- };
1371
- };
1372
- CatalogSimilarityMatch: {
1373
- coffee: {
1374
- id: number;
1375
- name: string;
1376
- source: string | null;
1377
- origin: string | null;
1378
- country: string | null;
1379
- continent: string | null;
1380
- processing: string | null;
1381
- processing_base_method: string | null;
1382
- fermentation_type: string | null;
1383
- drying_method: string | null;
1384
- stocked: boolean | null;
1385
- arrival_date: string | null;
1386
- stocked_date: string | null;
1387
- proof: {
1388
- /** @enum {string} */
1389
- version: "proof-summary-v1";
1390
- overall: {
1391
- /** @enum {string} */
1392
- label: "strong" | "partial" | "limited" | "not_available";
1393
- families_with_signals: number;
2223
+ 403: {
2224
+ headers: {
2225
+ [name: string]: unknown;
1394
2226
  };
1395
- families: {
1396
- process: {
1397
- label: string;
1398
- confidence: number | null;
1399
- signals: string[];
1400
- message: string;
1401
- };
1402
- provenance: {
1403
- label: string;
1404
- confidence: number | null;
1405
- signals: string[];
1406
- message: string;
1407
- };
1408
- freshness: {
1409
- label: string;
1410
- confidence: number | null;
1411
- signals: string[];
1412
- message: string;
1413
- };
1414
- pricing: {
1415
- label: string;
1416
- confidence: number | null;
1417
- signals: string[];
1418
- message: string;
1419
- };
2227
+ content: {
2228
+ "application/json": components["schemas"]["ErrorResponse"];
2229
+ };
2230
+ };
2231
+ 404: {
2232
+ headers: {
2233
+ [name: string]: unknown;
2234
+ };
2235
+ content: {
2236
+ "application/json": components["schemas"]["ErrorResponse"];
2237
+ };
2238
+ };
2239
+ 503: {
2240
+ headers: {
2241
+ [name: string]: unknown;
2242
+ };
2243
+ content: {
2244
+ "application/json": components["schemas"]["ErrorResponse"];
1420
2245
  };
1421
- limitations: string[];
1422
2246
  };
1423
2247
  };
1424
- pricing: {
1425
- price_per_lb: number | null;
1426
- price_tiers?: unknown;
1427
- cost_lb: number | null;
1428
- /** @enum {number} */
1429
- baseline_quantity_lbs: 1;
1430
- baseline_price_per_lb: number | null;
1431
- /** @enum {string|null} */
1432
- baseline_source: "price_per_lb" | "price_tiers" | "cost_lb" | null;
1433
- };
1434
- price_delta_1lb: {
1435
- amount: number | null;
1436
- percent: number | null;
1437
- /** @enum {string} */
1438
- currency: "USD";
2248
+ }> | undefined, `${string}/${string}`>>;
2249
+ /** Create an API key. The raw secret is returned only once. */
2250
+ create: (body: ApiKeyCreateRequest) => Promise<openapi_fetch.FetchResponse<{
2251
+ parameters: {
2252
+ query?: never;
2253
+ header?: never;
2254
+ path?: never;
2255
+ cookie?: never;
1439
2256
  };
1440
- score: {
1441
- average: number;
1442
- dimensions: {
1443
- origin: number | null;
1444
- processing: number | null;
1445
- tasting: number | null;
2257
+ requestBody: {
2258
+ content: {
2259
+ "application/json": {
2260
+ name: string;
2261
+ scopes?: "catalog:read"[];
2262
+ };
1446
2263
  };
1447
- chunk_matches: number;
1448
2264
  };
1449
- match: {
1450
- /** @enum {string} */
1451
- category: "likely_same" | "similar_profile";
1452
- classification: {
1453
- /** @enum {string} */
1454
- kind: "canonical_candidate" | "similar_recommendation";
1455
- /** @enum {string} */
1456
- identity_eligibility: "eligible" | "blocked" | "insufficient_evidence";
1457
- /** @enum {string} */
1458
- confidence: "high_beta" | "medium_beta" | "low_beta";
1459
- blockers: {
1460
- code: string;
1461
- /** @enum {string} */
1462
- severity: "hard" | "soft";
1463
- target_value: string | null;
1464
- candidate_value: string | null;
1465
- }[];
1466
- evidence: string[];
2265
+ responses: {
2266
+ 201: {
2267
+ headers: {
2268
+ [name: string]: unknown;
2269
+ };
2270
+ content: {
2271
+ "application/json": components["schemas"]["ApiKeyCreateResponse"];
2272
+ };
1467
2273
  };
1468
- /** @enum {string} */
1469
- confidence: "high_beta" | "medium_beta" | "low_beta";
1470
- /** @enum {boolean} */
1471
- beta: true;
1472
- language: string;
1473
- same_supplier: boolean;
1474
- };
1475
- explanation: {
1476
- summary: string;
1477
- signals: string[];
1478
- };
1479
- compatibility: {
1480
- cost_lb: number | null;
1481
- };
1482
- };
1483
- CatalogSimilarityResponse: {
1484
- data: {
1485
- target: components["schemas"]["CatalogSimilarityTarget"];
1486
- groups: {
1487
- canonical_candidates: components["schemas"]["CatalogSimilarityMatch"][];
1488
- similar_recommendations: components["schemas"]["CatalogSimilarityMatch"][];
2274
+ 400: {
2275
+ headers: {
2276
+ [name: string]: unknown;
2277
+ };
2278
+ content: {
2279
+ "application/json": components["schemas"]["ErrorResponse"];
2280
+ };
1489
2281
  };
1490
- matches: components["schemas"]["CatalogSimilarityMatch"][];
1491
- };
1492
- meta: {
1493
- /** @enum {string} */
1494
- resource: "catalog-similarity";
1495
- /** @enum {string} */
1496
- namespace: "/v1/catalog/{id}/similar";
1497
- /** @enum {string} */
1498
- version: "v1";
1499
- /** @enum {string} */
1500
- status: "beta";
1501
- auth: {
1502
- /** @enum {string} */
1503
- kind: "session" | "api-key";
1504
- /** @enum {string|null} */
1505
- role: "viewer" | "member" | "admin" | null;
1506
- /** @enum {string|null} */
1507
- apiPlan: "viewer" | "member" | "enterprise" | null;
2282
+ 401: {
2283
+ headers: {
2284
+ [name: string]: unknown;
2285
+ };
2286
+ content: {
2287
+ "application/json": components["schemas"]["ErrorResponse"];
2288
+ };
1508
2289
  };
1509
- access: {
1510
- /** @enum {string} */
1511
- requiredCapability: "canUseBeanMatching";
1512
- /** @enum {boolean} */
1513
- canUseBeanMatching: true;
2290
+ 403: {
2291
+ headers: {
2292
+ [name: string]: unknown;
2293
+ };
2294
+ content: {
2295
+ "application/json": components["schemas"]["ErrorResponse"];
2296
+ };
1514
2297
  };
1515
- query: {
1516
- threshold: number;
1517
- limit: number;
1518
- stockedOnly: boolean;
1519
- /** @enum {string} */
1520
- mode: "all" | "likely_same" | "similar_profile";
2298
+ 404: {
2299
+ headers: {
2300
+ [name: string]: unknown;
2301
+ };
2302
+ content: {
2303
+ "application/json": components["schemas"]["ErrorResponse"];
2304
+ };
1521
2305
  };
1522
- copy: {
1523
- confidence: string;
2306
+ 503: {
2307
+ headers: {
2308
+ [name: string]: unknown;
2309
+ };
2310
+ content: {
2311
+ "application/json": components["schemas"]["ErrorResponse"];
2312
+ };
1524
2313
  };
1525
- /** @enum {string} */
1526
- classification_version: "canonical-match-v1";
1527
- /** @enum {string} */
1528
- query_strategy: "bounded-vector-candidates-v1" | "canonical-vector-aggregated-v2" | "legacy-vector-aggregated-v1";
1529
2314
  };
1530
- };
1531
- SourcingBriefCriteria: {
1532
- /** @enum {number} */
1533
- version?: 1;
1534
- country?: string;
1535
- region?: string;
1536
- processing?: string;
1537
- processing_base_method?: string;
1538
- max_price_per_lb?: number;
1539
- stocked_only?: boolean;
1540
- wholesale_only?: boolean;
1541
- stocked_days?: number;
1542
- };
1543
- SourcingBriefResource: {
1544
- id: string;
1545
- name: string;
1546
- criteria: components["schemas"]["SourcingBriefCriteria"] & Record<string, never>;
1547
- /** @enum {string} */
1548
- cadence: "manual";
1549
- isActive: boolean;
1550
- lastRunAt: string | null;
1551
- createdAt: string;
1552
- updatedAt: string;
1553
- };
1554
- SourcingBriefsListResponse: {
1555
- data: components["schemas"]["SourcingBriefResource"][];
1556
- meta: {
1557
- /** @enum {string} */
1558
- resource: "procurement-briefs";
1559
- /** @enum {string} */
1560
- namespace: "/v1/procurement/briefs";
1561
- /** @enum {string} */
1562
- version: "v1";
1563
- auth: {
1564
- /** @enum {string} */
1565
- kind: "session" | "api-key";
1566
- /** @enum {string|null} */
1567
- role: "admin" | "member" | "viewer" | null;
1568
- /** @enum {string|null} */
1569
- apiPlan: "viewer" | "member" | "enterprise" | null;
2315
+ }, {
2316
+ body: {
2317
+ name: string;
2318
+ scopes?: "catalog:read"[];
2319
+ };
2320
+ }, `${string}/${string}`>>;
2321
+ /** Revoke an API key owned by the authenticated session user. */
2322
+ revoke: (id: string) => Promise<openapi_fetch.FetchResponse<{
2323
+ parameters: {
2324
+ query?: never;
2325
+ header?: never;
2326
+ path: {
2327
+ id: string;
1570
2328
  };
2329
+ cookie?: never;
1571
2330
  };
1572
- };
1573
- SourcingBriefResponse: {
1574
- data: components["schemas"]["SourcingBriefResource"];
1575
- meta: {
1576
- /** @enum {string} */
1577
- resource: "procurement-brief";
1578
- /** @enum {string} */
1579
- namespace: "/v1/procurement/briefs" | "/v1/procurement/briefs/:id";
1580
- /** @enum {string} */
1581
- version: "v1";
1582
- auth: {
1583
- /** @enum {string} */
1584
- kind: "session" | "api-key";
1585
- /** @enum {string|null} */
1586
- role: "admin" | "member" | "viewer" | null;
1587
- /** @enum {string|null} */
1588
- apiPlan: "viewer" | "member" | "enterprise" | null;
2331
+ requestBody?: never;
2332
+ responses: {
2333
+ 200: {
2334
+ headers: {
2335
+ [name: string]: unknown;
2336
+ };
2337
+ content: {
2338
+ "application/json": components["schemas"]["ApiKeyMutationResponse"];
2339
+ };
2340
+ };
2341
+ 400: {
2342
+ headers: {
2343
+ [name: string]: unknown;
2344
+ };
2345
+ content: {
2346
+ "application/json": components["schemas"]["ErrorResponse"];
2347
+ };
2348
+ };
2349
+ 401: {
2350
+ headers: {
2351
+ [name: string]: unknown;
2352
+ };
2353
+ content: {
2354
+ "application/json": components["schemas"]["ErrorResponse"];
2355
+ };
2356
+ };
2357
+ 403: {
2358
+ headers: {
2359
+ [name: string]: unknown;
2360
+ };
2361
+ content: {
2362
+ "application/json": components["schemas"]["ErrorResponse"];
2363
+ };
2364
+ };
2365
+ 404: {
2366
+ headers: {
2367
+ [name: string]: unknown;
2368
+ };
2369
+ content: {
2370
+ "application/json": components["schemas"]["ErrorResponse"];
2371
+ };
2372
+ };
2373
+ 503: {
2374
+ headers: {
2375
+ [name: string]: unknown;
2376
+ };
2377
+ content: {
2378
+ "application/json": components["schemas"]["ErrorResponse"];
2379
+ };
1589
2380
  };
1590
2381
  };
1591
- };
1592
- SourcingBriefCreateRequest: {
1593
- /** @description Human label, 1-120 chars. */
1594
- name: string;
1595
- criteria: components["schemas"]["SourcingBriefCriteria"] & unknown;
1596
- /** @enum {string} */
1597
- cadence?: "manual";
1598
- };
1599
- SourcingBriefMatch: {
1600
- id: number;
1601
- name?: string | null;
1602
- source?: string | null;
1603
- continent?: string | null;
1604
- country?: string | null;
1605
- region?: string | null;
1606
- processing?: string | null;
1607
- processing_base_method?: string | null;
1608
- fermentation_type?: string | null;
1609
- drying_method?: string | null;
1610
- cultivar_detail?: string | null;
1611
- type?: string | null;
1612
- grade?: string | null;
1613
- appearance?: string | null;
1614
- score_value?: number | null;
1615
- purveyor_score?: number | null;
1616
- cost_lb?: number | null;
1617
- price_per_lb?: number | null;
1618
- price_tiers?: unknown;
1619
- arrival_date?: string | null;
1620
- stocked_date?: string | null;
1621
- stocked?: boolean | null;
1622
- wholesale?: boolean | null;
1623
- public_coffee?: boolean | null;
1624
- matchReasons: string[];
1625
- };
1626
- SourcingBriefMatchesResponse: {
1627
- data: components["schemas"]["SourcingBriefMatch"][];
1628
- pagination: {
1629
- page: number;
1630
- limit: number;
1631
- total: number;
1632
- totalPages: number;
1633
- hasNext: boolean;
1634
- hasPrev: boolean;
2382
+ }, {
2383
+ params: {
2384
+ path: {
2385
+ id: string;
2386
+ };
1635
2387
  };
1636
- meta: {
1637
- /** @enum {string} */
1638
- resource: "procurement-brief-matches";
1639
- /** @enum {string} */
1640
- namespace: "/v1/procurement/briefs/:id/matches";
1641
- /** @enum {string} */
1642
- version: "v1";
1643
- generatedAt: string;
1644
- auth: {
1645
- /** @enum {string} */
1646
- kind: "session" | "api-key";
1647
- /** @enum {string|null} */
1648
- role: "admin" | "member" | "viewer" | null;
1649
- /** @enum {string|null} */
1650
- apiPlan: "viewer" | "member" | "enterprise" | null;
2388
+ }, `${string}/${string}`>>;
2389
+ /** Rotate an API key and return the replacement secret once. */
2390
+ rotate: (id: string) => Promise<openapi_fetch.FetchResponse<{
2391
+ parameters: {
2392
+ query?: never;
2393
+ header?: never;
2394
+ path: {
2395
+ id: string;
1651
2396
  };
1652
- brief: components["schemas"]["SourcingBriefResource"];
1653
- criteria: components["schemas"]["SourcingBriefCriteria"] & Record<string, never>;
1654
- limitations: string[];
2397
+ cookie?: never;
1655
2398
  };
1656
- };
1657
- };
1658
- responses: never;
1659
- parameters: never;
1660
- requestBodies: never;
1661
- headers: never;
1662
- pathItems: never;
1663
- }
1664
-
1665
- interface ParchmentClientOptions {
1666
- /** Base URL of the Parchment API, e.g. https://api.purveyors.io */
1667
- baseUrl: string;
1668
- /**
1669
- * Optional bearer token (a Supabase JWT or, later, an API key). Sent as
1670
- * `Authorization: Bearer <token>`. Auth is resolved server-side against the
1671
- * unified principal model; the SDK only forwards the credential.
1672
- */
1673
- token?: string;
1674
- /** Override the fetch implementation (useful for tests or custom runtimes). */
1675
- fetch?: ClientOptions["fetch"];
1676
- }
1677
- /** Query parameters for {@link ParchmentClient.catalog.list}. */
1678
- type CatalogListQuery = NonNullable<paths["/v1/catalog"]["get"]["parameters"]["query"]>;
1679
- /** Query parameters for {@link ParchmentClient.catalog.facets}. */
1680
- type CatalogFacetsQuery = NonNullable<paths["/v1/catalog/facets"]["get"]["parameters"]["query"]>;
1681
- /**
1682
- * Optional headers for {@link ParchmentClient.catalog.list}, notably the
1683
- * RFC 7240 `Prefer: handling=lenient|strict` override (PADR-0013 §7). Sending
1684
- * `handling=lenient` opts a strict caller (API key or bearer-session JWT) back
1685
- * into strip-with-notice degradation instead of a 401/403 hard-deny.
1686
- */
1687
- type CatalogListHeaders = NonNullable<paths["/v1/catalog"]["get"]["parameters"]["header"]>;
1688
- /** Optional headers for {@link ParchmentClient.catalog.facets}; see {@link CatalogListHeaders}. */
1689
- type CatalogFacetsHeaders = NonNullable<paths["/v1/catalog/facets"]["get"]["parameters"]["header"]>;
1690
- /** Query parameters for {@link ParchmentClient.catalog.originPriceStats}. */
1691
- type CatalogOriginPriceStatsQuery = NonNullable<paths["/v1/catalog/origin-price-stats"]["get"]["parameters"]["query"]>;
1692
- /** Query parameters for {@link ParchmentClient.catalog.similar}. */
1693
- type CatalogSimilarQuery = NonNullable<paths["/v1/catalog/{id}/similar"]["get"]["parameters"]["query"]>;
1694
- /** Query parameters for {@link ParchmentClient.priceIndex.list}. */
1695
- type PriceIndexQuery = NonNullable<paths["/v1/price-index"]["get"]["parameters"]["query"]>;
1696
- /** Query parameters for {@link ParchmentClient.procurement.briefs.matches}. */
1697
- type BriefMatchesQuery = NonNullable<paths["/v1/procurement/briefs/{id}/matches"]["get"]["parameters"]["query"]>;
1698
- /** Request body for {@link ParchmentClient.procurement.briefs.create}. */
1699
- type SourcingBriefCreateRequest = components["schemas"]["SourcingBriefCreateRequest"];
1700
- /**
1701
- * Create a typed Parchment API client.
1702
- *
1703
- * The generated core (openapi-fetch over the generated `paths` types) is the
1704
- * contract truth; the named helpers below are the hand-maintained ergonomic
1705
- * layer and grow as endpoints land. `raw` always exposes the underlying typed
1706
- * client for direct path access to anything not yet wrapped.
1707
- */
1708
- declare function createParchmentClient(options: ParchmentClientOptions): {
1709
- /** The underlying typed openapi-fetch client for direct path access. */
1710
- raw: openapi_fetch.Client<paths, `${string}/${string}`>;
1711
- /** Liveness and service identity. */
1712
- health: () => Promise<openapi_fetch.FetchResponse<{
1713
- parameters: {
1714
- query?: never;
1715
- header?: never;
1716
- path?: never;
1717
- cookie?: never;
1718
- };
1719
- requestBody?: never;
1720
- responses: {
1721
- 200: {
1722
- headers: {
1723
- [name: string]: unknown;
2399
+ requestBody?: never;
2400
+ responses: {
2401
+ 201: {
2402
+ headers: {
2403
+ [name: string]: unknown;
2404
+ };
2405
+ content: {
2406
+ "application/json": components["schemas"]["ApiKeyCreateResponse"];
2407
+ };
1724
2408
  };
1725
- content: {
1726
- "application/json": components["schemas"]["HealthResponse"];
2409
+ 400: {
2410
+ headers: {
2411
+ [name: string]: unknown;
2412
+ };
2413
+ content: {
2414
+ "application/json": components["schemas"]["ErrorResponse"];
2415
+ };
1727
2416
  };
1728
- };
1729
- };
1730
- }, openapi_fetch.FetchOptions<{
1731
- parameters: {
1732
- query?: never;
1733
- header?: never;
1734
- path?: never;
1735
- cookie?: never;
1736
- };
1737
- requestBody?: never;
1738
- responses: {
1739
- 200: {
1740
- headers: {
1741
- [name: string]: unknown;
2417
+ 401: {
2418
+ headers: {
2419
+ [name: string]: unknown;
2420
+ };
2421
+ content: {
2422
+ "application/json": components["schemas"]["ErrorResponse"];
2423
+ };
1742
2424
  };
1743
- content: {
1744
- "application/json": components["schemas"]["HealthResponse"];
2425
+ 403: {
2426
+ headers: {
2427
+ [name: string]: unknown;
2428
+ };
2429
+ content: {
2430
+ "application/json": components["schemas"]["ErrorResponse"];
2431
+ };
1745
2432
  };
1746
- };
1747
- };
1748
- }> | undefined, `${string}/${string}`>>;
1749
- /** Resolved principal and entitlements for the caller. */
1750
- me: () => Promise<openapi_fetch.FetchResponse<{
1751
- parameters: {
1752
- query?: never;
1753
- header?: never;
1754
- path?: never;
1755
- cookie?: never;
1756
- };
1757
- requestBody?: never;
1758
- responses: {
1759
- 200: {
1760
- headers: {
1761
- [name: string]: unknown;
2433
+ 404: {
2434
+ headers: {
2435
+ [name: string]: unknown;
2436
+ };
2437
+ content: {
2438
+ "application/json": components["schemas"]["ErrorResponse"];
2439
+ };
1762
2440
  };
1763
- content: {
1764
- "application/json": components["schemas"]["MeResponse"];
2441
+ 503: {
2442
+ headers: {
2443
+ [name: string]: unknown;
2444
+ };
2445
+ content: {
2446
+ "application/json": components["schemas"]["ErrorResponse"];
2447
+ };
1765
2448
  };
1766
2449
  };
1767
- };
1768
- }, openapi_fetch.FetchOptions<{
1769
- parameters: {
1770
- query?: never;
1771
- header?: never;
1772
- path?: never;
1773
- cookie?: never;
1774
- };
1775
- requestBody?: never;
1776
- responses: {
1777
- 200: {
1778
- headers: {
1779
- [name: string]: unknown;
1780
- };
1781
- content: {
1782
- "application/json": components["schemas"]["MeResponse"];
2450
+ }, {
2451
+ params: {
2452
+ path: {
2453
+ id: string;
1783
2454
  };
1784
2455
  };
1785
- };
1786
- }> | undefined, `${string}/${string}`>>;
2456
+ }, `${string}/${string}`>>;
2457
+ };
1787
2458
  catalog: {
1788
2459
  /** Catalog capabilities and visibility for the caller. */
1789
2460
  access: () => Promise<openapi_fetch.FetchResponse<{
1790
2461
  parameters: {
1791
2462
  query?: never;
1792
- header? /** Catalog capabilities and visibility for the caller. */: never;
2463
+ header?: never;
1793
2464
  path?: never;
1794
2465
  cookie?: never;
1795
2466
  };
@@ -1808,7 +2479,7 @@ declare function createParchmentClient(options: ParchmentClientOptions): {
1808
2479
  [name: string]: unknown;
1809
2480
  };
1810
2481
  content: {
1811
- "application/json": components["schemas"] /** Live catalog price context by origin. */["ErrorResponse"];
2482
+ "application/json": components["schemas"]["ErrorResponse"];
1812
2483
  };
1813
2484
  };
1814
2485
  403: {
@@ -1823,7 +2494,7 @@ declare function createParchmentClient(options: ParchmentClientOptions): {
1823
2494
  }, openapi_fetch.FetchOptions<{
1824
2495
  parameters: {
1825
2496
  query?: never;
1826
- header? /** Catalog capabilities and visibility for the caller. */: never;
2497
+ header?: never;
1827
2498
  path?: never;
1828
2499
  cookie?: never;
1829
2500
  };
@@ -1842,7 +2513,7 @@ declare function createParchmentClient(options: ParchmentClientOptions): {
1842
2513
  [name: string]: unknown;
1843
2514
  };
1844
2515
  content: {
1845
- "application/json": components["schemas"] /** Live catalog price context by origin. */["ErrorResponse"];
2516
+ "application/json": components["schemas"]["ErrorResponse"];
1846
2517
  };
1847
2518
  };
1848
2519
  403: {