@proveanything/smartlinks 1.13.9 → 1.13.11

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.
@@ -28,7 +28,7 @@ export declare namespace authKit {
28
28
  /** Verify phone verification code (public). */
29
29
  function verifyPhoneCode(clientId: string, phoneNumber: string, code: string): Promise<PhoneVerifyResponse>;
30
30
  /** Send a WhatsApp verification deep-link (public). */
31
- function sendWhatsApp(clientId: string, body: SendWhatsAppRequest): Promise<SendWhatsAppResponse>;
31
+ function sendWhatsApp(clientId: string, body?: SendWhatsAppRequest): Promise<SendWhatsAppResponse>;
32
32
  /** Manually verify WhatsApp token if inbound webhook path is unavailable (public). */
33
33
  function verifyWhatsApp(clientId: string, token: string, phoneNumber: string): Promise<VerifyWhatsAppResponse>;
34
34
  /** Poll WhatsApp verification status for a token (public). */
@@ -47,7 +47,7 @@ export var authKit;
47
47
  }
48
48
  authKit.verifyPhoneCode = verifyPhoneCode;
49
49
  /** Send a WhatsApp verification deep-link (public). */
50
- async function sendWhatsApp(clientId, body) {
50
+ async function sendWhatsApp(clientId, body = {}) {
51
51
  return post(`/authkit/${encodeURIComponent(clientId)}/auth/whatsapp/send`, body);
52
52
  }
53
53
  authKit.sendWhatsApp = sendWhatsApp;
@@ -21,7 +21,10 @@ export declare namespace interactions {
21
21
  function aggregateByOutcome(collectionId: string, body: AdminInteractionsAggregateRequest): Promise<AdminInteractionsAggregateResponse>;
22
22
  /**
23
23
  * POST /admin/collection/:collectionId/interactions/append
24
- * Appends one interaction event.
24
+ * Appends one interaction event.
25
+ *
26
+ * `interactionId` must reference an existing interaction type definition.
27
+ * This endpoint does not create interaction definitions.
25
28
  */
26
29
  function appendEvent(collectionId: string, body: AppendInteractionBody): Promise<{
27
30
  success: true;
@@ -30,13 +33,15 @@ export declare namespace interactions {
30
33
  success: true;
31
34
  }>;
32
35
  /**
33
- * POST /api/v1/public/collection/:collectionId/interactions/submit
34
- *
35
- * Submits an interaction event from a public/client-side context.
36
- * When the interaction has `allowAnonymousSubmit: true`, neither `userId` nor
37
- * `contactId` is required. Pass `anonId` inside `metadata` to enable
38
- * device-level deduplication via `uniquePerAnonId`.
39
- */
36
+ * POST /api/v1/public/collection/:collectionId/interactions/submit
37
+ *
38
+ * Submits an interaction event from a public/client-side context.
39
+ * `interactionId` must reference an existing interaction type definition.
40
+ * This endpoint does not create interaction definitions.
41
+ * When the interaction has `allowAnonymousSubmit: true`, neither `userId` nor
42
+ * `contactId` is required. Pass `anonId` inside `metadata` to enable
43
+ * device-level deduplication via `uniquePerAnonId`.
44
+ */
40
45
  function submitPublicEvent(collectionId: string, body: AppendInteractionBody): Promise<SubmitInteractionResponse | SubmitInteractionError>;
41
46
  function create(collectionId: string, body: CreateInteractionTypeBody): Promise<InteractionTypeRecord>;
42
47
  function list(collectionId: string, query?: ListInteractionTypesQuery): Promise<InteractionTypeList>;
@@ -54,7 +54,10 @@ export var interactions;
54
54
  // Deprecated endpoint removed: actorIdsByInteraction
55
55
  /**
56
56
  * POST /admin/collection/:collectionId/interactions/append
57
- * Appends one interaction event.
57
+ * Appends one interaction event.
58
+ *
59
+ * `interactionId` must reference an existing interaction type definition.
60
+ * This endpoint does not create interaction definitions.
58
61
  */
59
62
  async function appendEvent(collectionId, body) {
60
63
  if (!body.userId && !body.contactId) {
@@ -73,13 +76,15 @@ export var interactions;
73
76
  }
74
77
  interactions.updateEvent = updateEvent;
75
78
  /**
76
- * POST /api/v1/public/collection/:collectionId/interactions/submit
77
- *
78
- * Submits an interaction event from a public/client-side context.
79
- * When the interaction has `allowAnonymousSubmit: true`, neither `userId` nor
80
- * `contactId` is required. Pass `anonId` inside `metadata` to enable
81
- * device-level deduplication via `uniquePerAnonId`.
82
- */
79
+ * POST /api/v1/public/collection/:collectionId/interactions/submit
80
+ *
81
+ * Submits an interaction event from a public/client-side context.
82
+ * `interactionId` must reference an existing interaction type definition.
83
+ * This endpoint does not create interaction definitions.
84
+ * When the interaction has `allowAnonymousSubmit: true`, neither `userId` nor
85
+ * `contactId` is required. Pass `anonId` inside `metadata` to enable
86
+ * device-level deduplication via `uniquePerAnonId`.
87
+ */
83
88
  async function submitPublicEvent(collectionId, body) {
84
89
  const path = `/public/collection/${encodeURIComponent(collectionId)}/interactions/submit`;
85
90
  return post(path, body);
@@ -1,6 +1,6 @@
1
1
  # Smartlinks API Summary
2
2
 
3
- Version: 1.13.9 | Generated: 2026-05-12T11:17:48.753Z
3
+ Version: 1.13.11 | Generated: 2026-05-13T07:57:31.015Z
4
4
 
5
5
  This is a concise summary of all available API functions and types.
6
6
 
@@ -3027,8 +3027,8 @@ interface EmailVerifyTokenResponse {
3027
3027
  **SendWhatsAppRequest** (interface)
3028
3028
  ```typescript
3029
3029
  interface SendWhatsAppRequest {
3030
- phoneNumber: string
3031
- redirectUrl: string
3030
+ phoneNumber?: string
3031
+ redirectUrl?: string
3032
3032
  }
3033
3033
  ```
3034
3034
 
@@ -6689,13 +6689,6 @@ interface ProductFacetValue {
6689
6689
  }
6690
6690
  ```
6691
6691
 
6692
- **ProductFacetMap** (interface)
6693
- ```typescript
6694
- interface ProductFacetMap {
6695
- [facetKey: string]: ProductFacetValue[]
6696
- }
6697
- ```
6698
-
6699
6692
  **ProductQueryRequest** (interface)
6700
6693
  ```typescript
6701
6694
  interface ProductQueryRequest {
@@ -6782,6 +6775,8 @@ interface ProductQueryResponse {
6782
6775
 
6783
6776
  **ISODateString** = `string`
6784
6777
 
6778
+ **ProductFacetMap** = `Record<string, string[]>`
6779
+
6785
6780
  **ProductClaimCreateRequestBody** = `Omit<ProductClaimCreateInput, 'collectionId' | 'id'>`
6786
6781
 
6787
6782
  **ProductResponse** = `Product`
@@ -7522,18 +7517,14 @@ interface UserInfo {
7522
7517
  interface ProductInfo {
7523
7518
  id: string
7524
7519
  tags?: Record<string, any>
7525
- * Facet values assigned to this product.
7526
- * Shape mirrors `ProductFacetMap`: a map of facet key array of value objects.
7527
- * Each value object must have at minimum a `key` string property.
7520
+ * Facet assignments on this product: maps each facet key to an array of assigned
7521
+ * value slugs/keys. Matches the slim shape returned by the Products API.
7528
7522
  *
7529
7523
  * @example
7530
7524
  * ```ts
7531
- * {
7532
- * material: [{ key: 'cotton', name: 'Cotton' }],
7533
- * certifications: [{ key: 'organic', name: 'Organic' }, { key: 'recycled', name: 'Recycled' }]
7534
- * }
7525
+ * { material: ['cotton'], certifications: ['organic', 'recycled'] }
7535
7526
  * ```
7536
- facets?: Record<string, Array<{ key: string; [k: string]: unknown }>>
7527
+ facets?: Record<string, string[]>
7537
7528
  }
7538
7529
  ```
7539
7530
 
@@ -8201,7 +8192,7 @@ Send phone verification code (public).
8201
8192
  **verifyPhoneCode**(clientId: string, phoneNumber: string, code: string) → `Promise<PhoneVerifyResponse>`
8202
8193
  Verify phone verification code (public).
8203
8194
 
8204
- **sendWhatsApp**(clientId: string, body: SendWhatsAppRequest) → `Promise<SendWhatsAppResponse>`
8195
+ **sendWhatsApp**(clientId: string, body: SendWhatsAppRequest = {}) → `Promise<SendWhatsAppResponse>`
8205
8196
  Send a WhatsApp verification deep-link (public).
8206
8197
 
8207
8198
  **verifyWhatsApp**(clientId: string, token: string, phoneNumber: string) → `Promise<VerifyWhatsAppResponse>`
@@ -8812,54 +8803,54 @@ Legacy-friendly alias for aggregate().
8812
8803
 
8813
8804
  **appendEvent**(collectionId: string,
8814
8805
  body: AppendInteractionBody) → `Promise<`
8815
- POST /admin/collection/:collectionId/interactions/append Appends one interaction event.
8806
+ POST /admin/collection/:collectionId/interactions/append Appends one interaction event. `interactionId` must reference an existing interaction type definition. This endpoint does not create interaction definitions.
8816
8807
 
8817
8808
  **updateEvent**(collectionId: string,
8818
8809
  body: UpdateInteractionBody) → `Promise<`
8819
- POST /admin/collection/:collectionId/interactions/append Appends one interaction event.
8810
+ POST /admin/collection/:collectionId/interactions/append Appends one interaction event. `interactionId` must reference an existing interaction type definition. This endpoint does not create interaction definitions.
8820
8811
 
8821
8812
  **submitPublicEvent**(collectionId: string,
8822
8813
  body: AppendInteractionBody) → `Promise<SubmitInteractionResponse | SubmitInteractionError>`
8823
- POST /api/v1/public/collection/:collectionId/interactions/submit Submits an interaction event from a public/client-side context. When the interaction has `allowAnonymousSubmit: true`, neither `userId` nor `contactId` is required. Pass `anonId` inside `metadata` to enable device-level deduplication via `uniquePerAnonId`.
8814
+ POST /api/v1/public/collection/:collectionId/interactions/submit Submits an interaction event from a public/client-side context. `interactionId` must reference an existing interaction type definition. This endpoint does not create interaction definitions. When the interaction has `allowAnonymousSubmit: true`, neither `userId` nor `contactId` is required. Pass `anonId` inside `metadata` to enable device-level deduplication via `uniquePerAnonId`.
8824
8815
 
8825
8816
  **create**(collectionId: string,
8826
8817
  body: CreateInteractionTypeBody) → `Promise<InteractionTypeRecord>`
8827
- POST /api/v1/public/collection/:collectionId/interactions/submit Submits an interaction event from a public/client-side context. When the interaction has `allowAnonymousSubmit: true`, neither `userId` nor `contactId` is required. Pass `anonId` inside `metadata` to enable device-level deduplication via `uniquePerAnonId`.
8818
+ POST /api/v1/public/collection/:collectionId/interactions/submit Submits an interaction event from a public/client-side context. `interactionId` must reference an existing interaction type definition. This endpoint does not create interaction definitions. When the interaction has `allowAnonymousSubmit: true`, neither `userId` nor `contactId` is required. Pass `anonId` inside `metadata` to enable device-level deduplication via `uniquePerAnonId`.
8828
8819
 
8829
8820
  **list**(collectionId: string,
8830
8821
  query: ListInteractionTypesQuery = {}) → `Promise<InteractionTypeList>`
8831
- POST /api/v1/public/collection/:collectionId/interactions/submit Submits an interaction event from a public/client-side context. When the interaction has `allowAnonymousSubmit: true`, neither `userId` nor `contactId` is required. Pass `anonId` inside `metadata` to enable device-level deduplication via `uniquePerAnonId`.
8822
+ POST /api/v1/public/collection/:collectionId/interactions/submit Submits an interaction event from a public/client-side context. `interactionId` must reference an existing interaction type definition. This endpoint does not create interaction definitions. When the interaction has `allowAnonymousSubmit: true`, neither `userId` nor `contactId` is required. Pass `anonId` inside `metadata` to enable device-level deduplication via `uniquePerAnonId`.
8832
8823
 
8833
8824
  **get**(collectionId: string,
8834
8825
  id: string) → `Promise<InteractionTypeRecord>`
8835
- POST /api/v1/public/collection/:collectionId/interactions/submit Submits an interaction event from a public/client-side context. When the interaction has `allowAnonymousSubmit: true`, neither `userId` nor `contactId` is required. Pass `anonId` inside `metadata` to enable device-level deduplication via `uniquePerAnonId`.
8826
+ POST /api/v1/public/collection/:collectionId/interactions/submit Submits an interaction event from a public/client-side context. `interactionId` must reference an existing interaction type definition. This endpoint does not create interaction definitions. When the interaction has `allowAnonymousSubmit: true`, neither `userId` nor `contactId` is required. Pass `anonId` inside `metadata` to enable device-level deduplication via `uniquePerAnonId`.
8836
8827
 
8837
8828
  **update**(collectionId: string,
8838
8829
  id: string,
8839
8830
  patchBody: UpdateInteractionTypeBody) → `Promise<InteractionTypeRecord>`
8840
- POST /api/v1/public/collection/:collectionId/interactions/submit Submits an interaction event from a public/client-side context. When the interaction has `allowAnonymousSubmit: true`, neither `userId` nor `contactId` is required. Pass `anonId` inside `metadata` to enable device-level deduplication via `uniquePerAnonId`.
8831
+ POST /api/v1/public/collection/:collectionId/interactions/submit Submits an interaction event from a public/client-side context. `interactionId` must reference an existing interaction type definition. This endpoint does not create interaction definitions. When the interaction has `allowAnonymousSubmit: true`, neither `userId` nor `contactId` is required. Pass `anonId` inside `metadata` to enable device-level deduplication via `uniquePerAnonId`.
8841
8832
 
8842
8833
  **remove**(collectionId: string,
8843
8834
  id: string) → `Promise<void>`
8844
- POST /api/v1/public/collection/:collectionId/interactions/submit Submits an interaction event from a public/client-side context. When the interaction has `allowAnonymousSubmit: true`, neither `userId` nor `contactId` is required. Pass `anonId` inside `metadata` to enable device-level deduplication via `uniquePerAnonId`.
8835
+ POST /api/v1/public/collection/:collectionId/interactions/submit Submits an interaction event from a public/client-side context. `interactionId` must reference an existing interaction type definition. This endpoint does not create interaction definitions. When the interaction has `allowAnonymousSubmit: true`, neither `userId` nor `contactId` is required. Pass `anonId` inside `metadata` to enable device-level deduplication via `uniquePerAnonId`.
8845
8836
 
8846
8837
  **publicCountsByOutcome**(collectionId: string,
8847
8838
  body: PublicInteractionsCountsByOutcomeRequest,
8848
8839
  authToken?: string) → `Promise<OutcomeCount[]>`
8849
- POST /api/v1/public/collection/:collectionId/interactions/submit Submits an interaction event from a public/client-side context. When the interaction has `allowAnonymousSubmit: true`, neither `userId` nor `contactId` is required. Pass `anonId` inside `metadata` to enable device-level deduplication via `uniquePerAnonId`.
8840
+ POST /api/v1/public/collection/:collectionId/interactions/submit Submits an interaction event from a public/client-side context. `interactionId` must reference an existing interaction type definition. This endpoint does not create interaction definitions. When the interaction has `allowAnonymousSubmit: true`, neither `userId` nor `contactId` is required. Pass `anonId` inside `metadata` to enable device-level deduplication via `uniquePerAnonId`.
8850
8841
 
8851
8842
  **publicMyInteractions**(collectionId: string,
8852
8843
  body: PublicInteractionsByUserRequest,
8853
8844
  authToken?: string) → `Promise<InteractionEventRow[]>`
8854
- POST /api/v1/public/collection/:collectionId/interactions/submit Submits an interaction event from a public/client-side context. When the interaction has `allowAnonymousSubmit: true`, neither `userId` nor `contactId` is required. Pass `anonId` inside `metadata` to enable device-level deduplication via `uniquePerAnonId`.
8845
+ POST /api/v1/public/collection/:collectionId/interactions/submit Submits an interaction event from a public/client-side context. `interactionId` must reference an existing interaction type definition. This endpoint does not create interaction definitions. When the interaction has `allowAnonymousSubmit: true`, neither `userId` nor `contactId` is required. Pass `anonId` inside `metadata` to enable device-level deduplication via `uniquePerAnonId`.
8855
8846
 
8856
8847
  **publicList**(collectionId: string,
8857
8848
  query: ListInteractionTypesQuery = {}) → `Promise<InteractionTypeList>`
8858
- POST /api/v1/public/collection/:collectionId/interactions/submit Submits an interaction event from a public/client-side context. When the interaction has `allowAnonymousSubmit: true`, neither `userId` nor `contactId` is required. Pass `anonId` inside `metadata` to enable device-level deduplication via `uniquePerAnonId`.
8849
+ POST /api/v1/public/collection/:collectionId/interactions/submit Submits an interaction event from a public/client-side context. `interactionId` must reference an existing interaction type definition. This endpoint does not create interaction definitions. When the interaction has `allowAnonymousSubmit: true`, neither `userId` nor `contactId` is required. Pass `anonId` inside `metadata` to enable device-level deduplication via `uniquePerAnonId`.
8859
8850
 
8860
8851
  **publicGet**(collectionId: string,
8861
8852
  id: string) → `Promise<InteractionTypeRecord>`
8862
- POST /api/v1/public/collection/:collectionId/interactions/submit Submits an interaction event from a public/client-side context. When the interaction has `allowAnonymousSubmit: true`, neither `userId` nor `contactId` is required. Pass `anonId` inside `metadata` to enable device-level deduplication via `uniquePerAnonId`.
8853
+ POST /api/v1/public/collection/:collectionId/interactions/submit Submits an interaction event from a public/client-side context. `interactionId` must reference an existing interaction type definition. This endpoint does not create interaction definitions. When the interaction has `allowAnonymousSubmit: true`, neither `userId` nor `contactId` is required. Pass `anonId` inside `metadata` to enable device-level deduplication via `uniquePerAnonId`.
8863
8854
 
8864
8855
  ### jobs
8865
8856
 
@@ -225,6 +225,8 @@ await SL.appConfiguration.setConfig({
225
225
 
226
226
  ### Tracked Interactions
227
227
 
228
+ Use interaction IDs that are defined via `SL.interactions.create(...)` for the collection. Do not invent ad-hoc IDs in app code.
229
+
228
230
  | Interaction ID | Description |
229
231
  | -------------- | --------------------------------------------- |
230
232
  | `page-view` | Tracks each time a user views the public page |
@@ -86,10 +86,12 @@ Use these flows when you want low-friction verification before or without full a
86
86
  import { authKit } from '@proveanything/smartlinks';
87
87
 
88
88
  // 1) Send WhatsApp verification deep link
89
- const wa = await authKit.sendWhatsApp(clientId, {
90
- phoneNumber: '+447911123456',
91
- redirectUrl: 'https://app.example.com/checkout/continue',
92
- });
89
+ const wa = await authKit.sendWhatsApp(clientId);
90
+
91
+ // Optional: pass redirect context only
92
+ // const wa = await authKit.sendWhatsApp(clientId, {
93
+ // redirectUrl: 'https://app.example.com/checkout/continue',
94
+ // });
93
95
 
94
96
  // wa.waLink can be opened directly by the app/browser
95
97
  // Poll status while user switches to WhatsApp and back
@@ -15,15 +15,19 @@ Interactions have two distinct layers:
15
15
  | **Interaction Types** | Definitions stored in the database — configure an interaction's ID, permissions, and display metadata once per collection |
16
16
  | **Interaction Events** | Individual event records logged each time a user performs that interaction |
17
17
 
18
+ Critical rule: event `interactionId` values must reference an existing interaction type definition in that collection. Do not generate random IDs in app code and submit events against them.
19
+
18
20
  ```text
19
21
  ┌──────────────────────────────────────────────────────────────────┐
20
22
  │ Your App │
21
23
  │ │
22
24
  │ 1. Create type once: interactions.create(collectionId, { │
23
25
  │ id: 'vote', permissions: { uniquePerUser: true } }) │
26
+ │ -> definition exists in platform │
24
27
  │ │
25
28
  │ 2. Log events: interactions.appendEvent(collectionId, { │
26
29
  │ interactionId: 'vote', outcome: 'option-a', userId }) │
30
+ │ (must match the created definition ID) │
27
31
  │ │
28
32
  │ 3. Read results: interactions.countsByOutcome(collectionId, │
29
33
  │ { interactionId: 'vote' }) │
@@ -31,6 +35,14 @@ Interactions have two distinct layers:
31
35
  └──────────────────────────────────────────────────────────────────┘
32
36
  ```
33
37
 
38
+ ### Required Workflow (Do Not Invent IDs)
39
+
40
+ 1. Create an interaction type definition (admin endpoint) before recording any events.
41
+ 2. Reuse that same definition ID for every `appendEvent` / `submitPublicEvent` call.
42
+ 3. Treat unknown IDs as configuration errors, not as values your app should auto-create.
43
+
44
+ If your app currently hardcodes strings like `"poll"` or `"entry"`, make sure those IDs are actually created as interaction types during setup.
45
+
34
46
  ---
35
47
 
36
48
  ## Common Use Cases
@@ -101,6 +113,8 @@ const { items } = await SL.interactions.publicList(collectionId, { appId: 'my-ap
101
113
 
102
114
  ## Logging Events
103
115
 
116
+ Before logging events, ensure the referenced interaction type already exists. Event ingestion is not intended to create new interaction definitions.
117
+
104
118
  ### Admin Event Append
105
119
 
106
120
  Use on the server side or in admin flows. Requires `userId` **or** `contactId`.
@@ -166,7 +180,7 @@ await SL.interactions.updateEvent(collectionId, {
166
180
 
167
181
  | Field | Type | Required | Description |
168
182
  |-------|------|----------|-------------|
169
- | `interactionId` | string | ✅ | Which interaction type this event belongs to |
183
+ | `interactionId` | string | ✅ | Existing interaction type ID (must already be defined in this collection) |
170
184
  | `userId` or `contactId` | string | ✅ (one of) | The actor. `appendEvent` / `updateEvent` require one of these |
171
185
  | `appId` | string | ❌ | Scopes the event to your app |
172
186
  | `outcome` | string | ❌ | The result or choice — what `countsByOutcome()` aggregates |
@@ -120,6 +120,8 @@ const { items } = await SL.loyalty.publicGetMineHistory(collectionId, schemeId,
120
120
 
121
121
  Earning rules are the control plane that connects interactions to point awards. The server evaluates them automatically — your app never sets a point value directly.
122
122
 
123
+ Every `interactionId` in a loyalty rule must reference an existing interaction type definition in the same collection.
124
+
123
125
  ### Create a Rule
124
126
 
125
127
  ```typescript
@@ -227,6 +227,8 @@ See `docs/ai.md` for complete documentation.
227
227
 
228
228
  The `SL.interactions` namespace tracks user engagement — competition entries, votes, form submissions, warranty registrations. Events can trigger automated journeys and communications.
229
229
 
230
+ Important: create interaction type definitions first, then submit events using those existing IDs. Do not invent `interactionId` values in client code.
231
+
230
232
  Key functions: `submitPublicEvent()`, `appendEvent()` (admin), `countsByOutcome()`, `query()`.
231
233
 
232
234
  See `docs/interactions.md` for complete documentation.
@@ -590,6 +590,7 @@ When a user votes, publish to the channel:
590
590
  ```typescript
591
591
  const submitVote = async (option: string) => {
592
592
  // Record in SmartLinks
593
+ // 'poll' must already exist as an interaction type definition for this collection.
593
594
  await SL.interactions.submitPublicEvent(collectionId, {
594
595
  appId,
595
596
  interactionId: 'poll',
package/dist/openapi.yaml CHANGED
@@ -17871,9 +17871,6 @@ components:
17871
17871
  type: string
17872
17872
  redirectUrl:
17873
17873
  type: string
17874
- required:
17875
- - phoneNumber
17876
- - redirectUrl
17877
17874
  SendWhatsAppResponse:
17878
17875
  type: object
17879
17876
  properties:
@@ -23108,9 +23105,6 @@ components:
23108
23105
  required:
23109
23106
  - key
23110
23107
  - name
23111
- ProductFacetMap:
23112
- type: object
23113
- properties: {}
23114
23108
  ProductQueryRequest:
23115
23109
  type: object
23116
23110
  properties:
@@ -77,8 +77,8 @@ export interface EmailVerifyTokenResponse {
77
77
  }
78
78
  export type VerifyStatus = 'pending' | 'verified' | 'failed' | 'expired' | 'unknown';
79
79
  export interface SendWhatsAppRequest {
80
- phoneNumber: string;
81
- redirectUrl: string;
80
+ phoneNumber?: string;
81
+ redirectUrl?: string;
82
82
  }
83
83
  export interface SendWhatsAppResponse {
84
84
  waLink: string;
@@ -15,6 +15,10 @@ export interface AdditionalGtin {
15
15
  gtin: string;
16
16
  owner?: boolean | null;
17
17
  }
18
+ /**
19
+ * Full facet value definition — returned by the Facets API.
20
+ * Not embedded in product responses; use ProductFacetMap for product-level assignments.
21
+ */
18
22
  export interface ProductFacetValue {
19
23
  id?: string;
20
24
  key: string;
@@ -25,9 +29,14 @@ export interface ProductFacetValue {
25
29
  color?: string;
26
30
  icon?: string;
27
31
  }
28
- export interface ProductFacetMap {
29
- [facetKey: string]: ProductFacetValue[];
30
- }
32
+ /**
33
+ * Slim facet assignments on a product: maps each facet key to an array of assigned
34
+ * value slugs/keys. Full value metadata lives in the Facets API.
35
+ *
36
+ * @example
37
+ * { type: ['website'], certifications: ['organic', 'recycled'] }
38
+ */
39
+ export type ProductFacetMap = Record<string, string[]>;
31
40
  export interface ProductQueryRequest {
32
41
  query?: {
33
42
  search?: string;
@@ -219,22 +219,15 @@ export interface ProductInfo {
219
219
  id: string;
220
220
  tags?: Record<string, any>;
221
221
  /**
222
- * Facet values assigned to this product.
223
- * Shape mirrors `ProductFacetMap`: a map of facet key array of value objects.
224
- * Each value object must have at minimum a `key` string property.
222
+ * Facet assignments on this product: maps each facet key to an array of assigned
223
+ * value slugs/keys. Matches the slim shape returned by the Products API.
225
224
  *
226
225
  * @example
227
226
  * ```ts
228
- * {
229
- * material: [{ key: 'cotton', name: 'Cotton' }],
230
- * certifications: [{ key: 'organic', name: 'Organic' }, { key: 'recycled', name: 'Recycled' }]
231
- * }
227
+ * { material: ['cotton'], certifications: ['organic', 'recycled'] }
232
228
  * ```
233
229
  */
234
- facets?: Record<string, Array<{
235
- key: string;
236
- [k: string]: unknown;
237
- }>>;
230
+ facets?: Record<string, string[]>;
238
231
  }
239
232
  /**
240
233
  * Proof information for condition validation
@@ -753,20 +753,19 @@ async function validateFacet(condition, params) {
753
753
  context: { facetKey, matchMode },
754
754
  };
755
755
  }
756
- const assigned = (_c = facets === null || facets === void 0 ? void 0 : facets[facetKey]) !== null && _c !== void 0 ? _c : [];
757
- const assignedKeys = assigned.map(v => v.key);
756
+ const assignedKeys = (_c = facets === null || facets === void 0 ? void 0 : facets[facetKey]) !== null && _c !== void 0 ? _c : [];
758
757
  // Presence-only modes — ignore `values`
759
758
  if (matchMode === 'hasFacet') {
760
759
  return {
761
760
  passed: assignedKeys.length > 0,
762
- detail: `Product ${assigned.length > 0 ? 'has' : 'does not have'} values on facet '${facetKey}'.`,
761
+ detail: `Product ${assignedKeys.length > 0 ? 'has' : 'does not have'} values on facet '${facetKey}'.`,
763
762
  context: { facetKey, assignedKeys },
764
763
  };
765
764
  }
766
765
  if (matchMode === 'notHasFacet') {
767
766
  return {
768
767
  passed: assignedKeys.length === 0,
769
- detail: `Product ${assigned.length === 0 ? 'has no' : 'has'} values on facet '${facetKey}'.`,
768
+ detail: `Product ${assignedKeys.length === 0 ? 'has no' : 'has'} values on facet '${facetKey}'.`,
770
769
  context: { facetKey, assignedKeys },
771
770
  };
772
771
  }
@@ -1,6 +1,6 @@
1
1
  # Smartlinks API Summary
2
2
 
3
- Version: 1.13.9 | Generated: 2026-05-12T11:17:48.753Z
3
+ Version: 1.13.11 | Generated: 2026-05-13T07:57:31.015Z
4
4
 
5
5
  This is a concise summary of all available API functions and types.
6
6
 
@@ -3027,8 +3027,8 @@ interface EmailVerifyTokenResponse {
3027
3027
  **SendWhatsAppRequest** (interface)
3028
3028
  ```typescript
3029
3029
  interface SendWhatsAppRequest {
3030
- phoneNumber: string
3031
- redirectUrl: string
3030
+ phoneNumber?: string
3031
+ redirectUrl?: string
3032
3032
  }
3033
3033
  ```
3034
3034
 
@@ -6689,13 +6689,6 @@ interface ProductFacetValue {
6689
6689
  }
6690
6690
  ```
6691
6691
 
6692
- **ProductFacetMap** (interface)
6693
- ```typescript
6694
- interface ProductFacetMap {
6695
- [facetKey: string]: ProductFacetValue[]
6696
- }
6697
- ```
6698
-
6699
6692
  **ProductQueryRequest** (interface)
6700
6693
  ```typescript
6701
6694
  interface ProductQueryRequest {
@@ -6782,6 +6775,8 @@ interface ProductQueryResponse {
6782
6775
 
6783
6776
  **ISODateString** = `string`
6784
6777
 
6778
+ **ProductFacetMap** = `Record<string, string[]>`
6779
+
6785
6780
  **ProductClaimCreateRequestBody** = `Omit<ProductClaimCreateInput, 'collectionId' | 'id'>`
6786
6781
 
6787
6782
  **ProductResponse** = `Product`
@@ -7522,18 +7517,14 @@ interface UserInfo {
7522
7517
  interface ProductInfo {
7523
7518
  id: string
7524
7519
  tags?: Record<string, any>
7525
- * Facet values assigned to this product.
7526
- * Shape mirrors `ProductFacetMap`: a map of facet key array of value objects.
7527
- * Each value object must have at minimum a `key` string property.
7520
+ * Facet assignments on this product: maps each facet key to an array of assigned
7521
+ * value slugs/keys. Matches the slim shape returned by the Products API.
7528
7522
  *
7529
7523
  * @example
7530
7524
  * ```ts
7531
- * {
7532
- * material: [{ key: 'cotton', name: 'Cotton' }],
7533
- * certifications: [{ key: 'organic', name: 'Organic' }, { key: 'recycled', name: 'Recycled' }]
7534
- * }
7525
+ * { material: ['cotton'], certifications: ['organic', 'recycled'] }
7535
7526
  * ```
7536
- facets?: Record<string, Array<{ key: string; [k: string]: unknown }>>
7527
+ facets?: Record<string, string[]>
7537
7528
  }
7538
7529
  ```
7539
7530
 
@@ -8201,7 +8192,7 @@ Send phone verification code (public).
8201
8192
  **verifyPhoneCode**(clientId: string, phoneNumber: string, code: string) → `Promise<PhoneVerifyResponse>`
8202
8193
  Verify phone verification code (public).
8203
8194
 
8204
- **sendWhatsApp**(clientId: string, body: SendWhatsAppRequest) → `Promise<SendWhatsAppResponse>`
8195
+ **sendWhatsApp**(clientId: string, body: SendWhatsAppRequest = {}) → `Promise<SendWhatsAppResponse>`
8205
8196
  Send a WhatsApp verification deep-link (public).
8206
8197
 
8207
8198
  **verifyWhatsApp**(clientId: string, token: string, phoneNumber: string) → `Promise<VerifyWhatsAppResponse>`
@@ -8812,54 +8803,54 @@ Legacy-friendly alias for aggregate().
8812
8803
 
8813
8804
  **appendEvent**(collectionId: string,
8814
8805
  body: AppendInteractionBody) → `Promise<`
8815
- POST /admin/collection/:collectionId/interactions/append Appends one interaction event.
8806
+ POST /admin/collection/:collectionId/interactions/append Appends one interaction event. `interactionId` must reference an existing interaction type definition. This endpoint does not create interaction definitions.
8816
8807
 
8817
8808
  **updateEvent**(collectionId: string,
8818
8809
  body: UpdateInteractionBody) → `Promise<`
8819
- POST /admin/collection/:collectionId/interactions/append Appends one interaction event.
8810
+ POST /admin/collection/:collectionId/interactions/append Appends one interaction event. `interactionId` must reference an existing interaction type definition. This endpoint does not create interaction definitions.
8820
8811
 
8821
8812
  **submitPublicEvent**(collectionId: string,
8822
8813
  body: AppendInteractionBody) → `Promise<SubmitInteractionResponse | SubmitInteractionError>`
8823
- POST /api/v1/public/collection/:collectionId/interactions/submit Submits an interaction event from a public/client-side context. When the interaction has `allowAnonymousSubmit: true`, neither `userId` nor `contactId` is required. Pass `anonId` inside `metadata` to enable device-level deduplication via `uniquePerAnonId`.
8814
+ POST /api/v1/public/collection/:collectionId/interactions/submit Submits an interaction event from a public/client-side context. `interactionId` must reference an existing interaction type definition. This endpoint does not create interaction definitions. When the interaction has `allowAnonymousSubmit: true`, neither `userId` nor `contactId` is required. Pass `anonId` inside `metadata` to enable device-level deduplication via `uniquePerAnonId`.
8824
8815
 
8825
8816
  **create**(collectionId: string,
8826
8817
  body: CreateInteractionTypeBody) → `Promise<InteractionTypeRecord>`
8827
- POST /api/v1/public/collection/:collectionId/interactions/submit Submits an interaction event from a public/client-side context. When the interaction has `allowAnonymousSubmit: true`, neither `userId` nor `contactId` is required. Pass `anonId` inside `metadata` to enable device-level deduplication via `uniquePerAnonId`.
8818
+ POST /api/v1/public/collection/:collectionId/interactions/submit Submits an interaction event from a public/client-side context. `interactionId` must reference an existing interaction type definition. This endpoint does not create interaction definitions. When the interaction has `allowAnonymousSubmit: true`, neither `userId` nor `contactId` is required. Pass `anonId` inside `metadata` to enable device-level deduplication via `uniquePerAnonId`.
8828
8819
 
8829
8820
  **list**(collectionId: string,
8830
8821
  query: ListInteractionTypesQuery = {}) → `Promise<InteractionTypeList>`
8831
- POST /api/v1/public/collection/:collectionId/interactions/submit Submits an interaction event from a public/client-side context. When the interaction has `allowAnonymousSubmit: true`, neither `userId` nor `contactId` is required. Pass `anonId` inside `metadata` to enable device-level deduplication via `uniquePerAnonId`.
8822
+ POST /api/v1/public/collection/:collectionId/interactions/submit Submits an interaction event from a public/client-side context. `interactionId` must reference an existing interaction type definition. This endpoint does not create interaction definitions. When the interaction has `allowAnonymousSubmit: true`, neither `userId` nor `contactId` is required. Pass `anonId` inside `metadata` to enable device-level deduplication via `uniquePerAnonId`.
8832
8823
 
8833
8824
  **get**(collectionId: string,
8834
8825
  id: string) → `Promise<InteractionTypeRecord>`
8835
- POST /api/v1/public/collection/:collectionId/interactions/submit Submits an interaction event from a public/client-side context. When the interaction has `allowAnonymousSubmit: true`, neither `userId` nor `contactId` is required. Pass `anonId` inside `metadata` to enable device-level deduplication via `uniquePerAnonId`.
8826
+ POST /api/v1/public/collection/:collectionId/interactions/submit Submits an interaction event from a public/client-side context. `interactionId` must reference an existing interaction type definition. This endpoint does not create interaction definitions. When the interaction has `allowAnonymousSubmit: true`, neither `userId` nor `contactId` is required. Pass `anonId` inside `metadata` to enable device-level deduplication via `uniquePerAnonId`.
8836
8827
 
8837
8828
  **update**(collectionId: string,
8838
8829
  id: string,
8839
8830
  patchBody: UpdateInteractionTypeBody) → `Promise<InteractionTypeRecord>`
8840
- POST /api/v1/public/collection/:collectionId/interactions/submit Submits an interaction event from a public/client-side context. When the interaction has `allowAnonymousSubmit: true`, neither `userId` nor `contactId` is required. Pass `anonId` inside `metadata` to enable device-level deduplication via `uniquePerAnonId`.
8831
+ POST /api/v1/public/collection/:collectionId/interactions/submit Submits an interaction event from a public/client-side context. `interactionId` must reference an existing interaction type definition. This endpoint does not create interaction definitions. When the interaction has `allowAnonymousSubmit: true`, neither `userId` nor `contactId` is required. Pass `anonId` inside `metadata` to enable device-level deduplication via `uniquePerAnonId`.
8841
8832
 
8842
8833
  **remove**(collectionId: string,
8843
8834
  id: string) → `Promise<void>`
8844
- POST /api/v1/public/collection/:collectionId/interactions/submit Submits an interaction event from a public/client-side context. When the interaction has `allowAnonymousSubmit: true`, neither `userId` nor `contactId` is required. Pass `anonId` inside `metadata` to enable device-level deduplication via `uniquePerAnonId`.
8835
+ POST /api/v1/public/collection/:collectionId/interactions/submit Submits an interaction event from a public/client-side context. `interactionId` must reference an existing interaction type definition. This endpoint does not create interaction definitions. When the interaction has `allowAnonymousSubmit: true`, neither `userId` nor `contactId` is required. Pass `anonId` inside `metadata` to enable device-level deduplication via `uniquePerAnonId`.
8845
8836
 
8846
8837
  **publicCountsByOutcome**(collectionId: string,
8847
8838
  body: PublicInteractionsCountsByOutcomeRequest,
8848
8839
  authToken?: string) → `Promise<OutcomeCount[]>`
8849
- POST /api/v1/public/collection/:collectionId/interactions/submit Submits an interaction event from a public/client-side context. When the interaction has `allowAnonymousSubmit: true`, neither `userId` nor `contactId` is required. Pass `anonId` inside `metadata` to enable device-level deduplication via `uniquePerAnonId`.
8840
+ POST /api/v1/public/collection/:collectionId/interactions/submit Submits an interaction event from a public/client-side context. `interactionId` must reference an existing interaction type definition. This endpoint does not create interaction definitions. When the interaction has `allowAnonymousSubmit: true`, neither `userId` nor `contactId` is required. Pass `anonId` inside `metadata` to enable device-level deduplication via `uniquePerAnonId`.
8850
8841
 
8851
8842
  **publicMyInteractions**(collectionId: string,
8852
8843
  body: PublicInteractionsByUserRequest,
8853
8844
  authToken?: string) → `Promise<InteractionEventRow[]>`
8854
- POST /api/v1/public/collection/:collectionId/interactions/submit Submits an interaction event from a public/client-side context. When the interaction has `allowAnonymousSubmit: true`, neither `userId` nor `contactId` is required. Pass `anonId` inside `metadata` to enable device-level deduplication via `uniquePerAnonId`.
8845
+ POST /api/v1/public/collection/:collectionId/interactions/submit Submits an interaction event from a public/client-side context. `interactionId` must reference an existing interaction type definition. This endpoint does not create interaction definitions. When the interaction has `allowAnonymousSubmit: true`, neither `userId` nor `contactId` is required. Pass `anonId` inside `metadata` to enable device-level deduplication via `uniquePerAnonId`.
8855
8846
 
8856
8847
  **publicList**(collectionId: string,
8857
8848
  query: ListInteractionTypesQuery = {}) → `Promise<InteractionTypeList>`
8858
- POST /api/v1/public/collection/:collectionId/interactions/submit Submits an interaction event from a public/client-side context. When the interaction has `allowAnonymousSubmit: true`, neither `userId` nor `contactId` is required. Pass `anonId` inside `metadata` to enable device-level deduplication via `uniquePerAnonId`.
8849
+ POST /api/v1/public/collection/:collectionId/interactions/submit Submits an interaction event from a public/client-side context. `interactionId` must reference an existing interaction type definition. This endpoint does not create interaction definitions. When the interaction has `allowAnonymousSubmit: true`, neither `userId` nor `contactId` is required. Pass `anonId` inside `metadata` to enable device-level deduplication via `uniquePerAnonId`.
8859
8850
 
8860
8851
  **publicGet**(collectionId: string,
8861
8852
  id: string) → `Promise<InteractionTypeRecord>`
8862
- POST /api/v1/public/collection/:collectionId/interactions/submit Submits an interaction event from a public/client-side context. When the interaction has `allowAnonymousSubmit: true`, neither `userId` nor `contactId` is required. Pass `anonId` inside `metadata` to enable device-level deduplication via `uniquePerAnonId`.
8853
+ POST /api/v1/public/collection/:collectionId/interactions/submit Submits an interaction event from a public/client-side context. `interactionId` must reference an existing interaction type definition. This endpoint does not create interaction definitions. When the interaction has `allowAnonymousSubmit: true`, neither `userId` nor `contactId` is required. Pass `anonId` inside `metadata` to enable device-level deduplication via `uniquePerAnonId`.
8863
8854
 
8864
8855
  ### jobs
8865
8856
 
@@ -225,6 +225,8 @@ await SL.appConfiguration.setConfig({
225
225
 
226
226
  ### Tracked Interactions
227
227
 
228
+ Use interaction IDs that are defined via `SL.interactions.create(...)` for the collection. Do not invent ad-hoc IDs in app code.
229
+
228
230
  | Interaction ID | Description |
229
231
  | -------------- | --------------------------------------------- |
230
232
  | `page-view` | Tracks each time a user views the public page |
package/docs/auth-kit.md CHANGED
@@ -86,10 +86,12 @@ Use these flows when you want low-friction verification before or without full a
86
86
  import { authKit } from '@proveanything/smartlinks';
87
87
 
88
88
  // 1) Send WhatsApp verification deep link
89
- const wa = await authKit.sendWhatsApp(clientId, {
90
- phoneNumber: '+447911123456',
91
- redirectUrl: 'https://app.example.com/checkout/continue',
92
- });
89
+ const wa = await authKit.sendWhatsApp(clientId);
90
+
91
+ // Optional: pass redirect context only
92
+ // const wa = await authKit.sendWhatsApp(clientId, {
93
+ // redirectUrl: 'https://app.example.com/checkout/continue',
94
+ // });
93
95
 
94
96
  // wa.waLink can be opened directly by the app/browser
95
97
  // Poll status while user switches to WhatsApp and back
@@ -15,15 +15,19 @@ Interactions have two distinct layers:
15
15
  | **Interaction Types** | Definitions stored in the database — configure an interaction's ID, permissions, and display metadata once per collection |
16
16
  | **Interaction Events** | Individual event records logged each time a user performs that interaction |
17
17
 
18
+ Critical rule: event `interactionId` values must reference an existing interaction type definition in that collection. Do not generate random IDs in app code and submit events against them.
19
+
18
20
  ```text
19
21
  ┌──────────────────────────────────────────────────────────────────┐
20
22
  │ Your App │
21
23
  │ │
22
24
  │ 1. Create type once: interactions.create(collectionId, { │
23
25
  │ id: 'vote', permissions: { uniquePerUser: true } }) │
26
+ │ -> definition exists in platform │
24
27
  │ │
25
28
  │ 2. Log events: interactions.appendEvent(collectionId, { │
26
29
  │ interactionId: 'vote', outcome: 'option-a', userId }) │
30
+ │ (must match the created definition ID) │
27
31
  │ │
28
32
  │ 3. Read results: interactions.countsByOutcome(collectionId, │
29
33
  │ { interactionId: 'vote' }) │
@@ -31,6 +35,14 @@ Interactions have two distinct layers:
31
35
  └──────────────────────────────────────────────────────────────────┘
32
36
  ```
33
37
 
38
+ ### Required Workflow (Do Not Invent IDs)
39
+
40
+ 1. Create an interaction type definition (admin endpoint) before recording any events.
41
+ 2. Reuse that same definition ID for every `appendEvent` / `submitPublicEvent` call.
42
+ 3. Treat unknown IDs as configuration errors, not as values your app should auto-create.
43
+
44
+ If your app currently hardcodes strings like `"poll"` or `"entry"`, make sure those IDs are actually created as interaction types during setup.
45
+
34
46
  ---
35
47
 
36
48
  ## Common Use Cases
@@ -101,6 +113,8 @@ const { items } = await SL.interactions.publicList(collectionId, { appId: 'my-ap
101
113
 
102
114
  ## Logging Events
103
115
 
116
+ Before logging events, ensure the referenced interaction type already exists. Event ingestion is not intended to create new interaction definitions.
117
+
104
118
  ### Admin Event Append
105
119
 
106
120
  Use on the server side or in admin flows. Requires `userId` **or** `contactId`.
@@ -166,7 +180,7 @@ await SL.interactions.updateEvent(collectionId, {
166
180
 
167
181
  | Field | Type | Required | Description |
168
182
  |-------|------|----------|-------------|
169
- | `interactionId` | string | ✅ | Which interaction type this event belongs to |
183
+ | `interactionId` | string | ✅ | Existing interaction type ID (must already be defined in this collection) |
170
184
  | `userId` or `contactId` | string | ✅ (one of) | The actor. `appendEvent` / `updateEvent` require one of these |
171
185
  | `appId` | string | ❌ | Scopes the event to your app |
172
186
  | `outcome` | string | ❌ | The result or choice — what `countsByOutcome()` aggregates |
package/docs/loyalty.md CHANGED
@@ -120,6 +120,8 @@ const { items } = await SL.loyalty.publicGetMineHistory(collectionId, schemeId,
120
120
 
121
121
  Earning rules are the control plane that connects interactions to point awards. The server evaluates them automatically — your app never sets a point value directly.
122
122
 
123
+ Every `interactionId` in a loyalty rule must reference an existing interaction type definition in the same collection.
124
+
123
125
  ### Create a Rule
124
126
 
125
127
  ```typescript
package/docs/overview.md CHANGED
@@ -227,6 +227,8 @@ See `docs/ai.md` for complete documentation.
227
227
 
228
228
  The `SL.interactions` namespace tracks user engagement — competition entries, votes, form submissions, warranty registrations. Events can trigger automated journeys and communications.
229
229
 
230
+ Important: create interaction type definitions first, then submit events using those existing IDs. Do not invent `interactionId` values in client code.
231
+
230
232
  Key functions: `submitPublicEvent()`, `appendEvent()` (admin), `countsByOutcome()`, `query()`.
231
233
 
232
234
  See `docs/interactions.md` for complete documentation.
package/docs/realtime.md CHANGED
@@ -590,6 +590,7 @@ When a user votes, publish to the channel:
590
590
  ```typescript
591
591
  const submitVote = async (option: string) => {
592
592
  // Record in SmartLinks
593
+ // 'poll' must already exist as an interaction type definition for this collection.
593
594
  await SL.interactions.submitPublicEvent(collectionId, {
594
595
  appId,
595
596
  interactionId: 'poll',
package/openapi.yaml CHANGED
@@ -17871,9 +17871,6 @@ components:
17871
17871
  type: string
17872
17872
  redirectUrl:
17873
17873
  type: string
17874
- required:
17875
- - phoneNumber
17876
- - redirectUrl
17877
17874
  SendWhatsAppResponse:
17878
17875
  type: object
17879
17876
  properties:
@@ -23108,9 +23105,6 @@ components:
23108
23105
  required:
23109
23106
  - key
23110
23107
  - name
23111
- ProductFacetMap:
23112
- type: object
23113
- properties: {}
23114
23108
  ProductQueryRequest:
23115
23109
  type: object
23116
23110
  properties:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@proveanything/smartlinks",
3
- "version": "1.13.9",
3
+ "version": "1.13.11",
4
4
  "description": "Official JavaScript/TypeScript SDK for the Smartlinks API",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",