@proveanything/smartlinks 1.13.10 → 1.13.12

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.10 | Generated: 2026-05-12T16:12:33.784Z
3
+ Version: 1.13.12 | Generated: 2026-05-14T16:00:33.063Z
4
4
 
5
5
  This is a concise summary of all available API functions and types.
6
6
 
@@ -3024,11 +3024,31 @@ interface EmailVerifyTokenResponse {
3024
3024
  }
3025
3025
  ```
3026
3026
 
3027
+ **WhatsAppReplyCta** (interface)
3028
+ ```typescript
3029
+ interface WhatsAppReplyCta {
3030
+ body: string
3031
+ buttonLabel: string
3032
+ buttonUrl: string
3033
+ }
3034
+ ```
3035
+
3036
+ **WhatsAppReplyOptions** (interface)
3037
+ ```typescript
3038
+ interface WhatsAppReplyOptions {
3039
+ contentSid?: string
3040
+ contentVariables?: Record<string, unknown>
3041
+ cta?: WhatsAppReplyCta
3042
+ text?: string
3043
+ }
3044
+ ```
3045
+
3027
3046
  **SendWhatsAppRequest** (interface)
3028
3047
  ```typescript
3029
3048
  interface SendWhatsAppRequest {
3030
- phoneNumber: string
3031
- redirectUrl: string
3049
+ phoneNumber?: string
3050
+ redirectUrl?: string
3051
+ reply?: WhatsAppReplyOptions
3032
3052
  }
3033
3053
  ```
3034
3054
 
@@ -8192,7 +8212,7 @@ Send phone verification code (public).
8192
8212
  **verifyPhoneCode**(clientId: string, phoneNumber: string, code: string) → `Promise<PhoneVerifyResponse>`
8193
8213
  Verify phone verification code (public).
8194
8214
 
8195
- **sendWhatsApp**(clientId: string, body: SendWhatsAppRequest) → `Promise<SendWhatsAppResponse>`
8215
+ **sendWhatsApp**(clientId: string, body: SendWhatsAppRequest = {}) → `Promise<SendWhatsAppResponse>`
8196
8216
  Send a WhatsApp verification deep-link (public).
8197
8217
 
8198
8218
  **verifyWhatsApp**(clientId: string, token: string, phoneNumber: string) → `Promise<VerifyWhatsAppResponse>`
@@ -8803,54 +8823,54 @@ Legacy-friendly alias for aggregate().
8803
8823
 
8804
8824
  **appendEvent**(collectionId: string,
8805
8825
  body: AppendInteractionBody) → `Promise<`
8806
- POST /admin/collection/:collectionId/interactions/append Appends one interaction event.
8826
+ 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.
8807
8827
 
8808
8828
  **updateEvent**(collectionId: string,
8809
8829
  body: UpdateInteractionBody) → `Promise<`
8810
- POST /admin/collection/:collectionId/interactions/append Appends one interaction event.
8830
+ 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.
8811
8831
 
8812
8832
  **submitPublicEvent**(collectionId: string,
8813
8833
  body: AppendInteractionBody) → `Promise<SubmitInteractionResponse | SubmitInteractionError>`
8814
- 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`.
8834
+ 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`.
8815
8835
 
8816
8836
  **create**(collectionId: string,
8817
8837
  body: CreateInteractionTypeBody) → `Promise<InteractionTypeRecord>`
8818
- 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`.
8838
+ 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`.
8819
8839
 
8820
8840
  **list**(collectionId: string,
8821
8841
  query: ListInteractionTypesQuery = {}) → `Promise<InteractionTypeList>`
8822
- 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`.
8842
+ 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`.
8823
8843
 
8824
8844
  **get**(collectionId: string,
8825
8845
  id: string) → `Promise<InteractionTypeRecord>`
8826
- 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`.
8846
+ 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`.
8827
8847
 
8828
8848
  **update**(collectionId: string,
8829
8849
  id: string,
8830
8850
  patchBody: UpdateInteractionTypeBody) → `Promise<InteractionTypeRecord>`
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`.
8851
+ 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
8852
 
8833
8853
  **remove**(collectionId: string,
8834
8854
  id: string) → `Promise<void>`
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`.
8855
+ 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
8856
 
8837
8857
  **publicCountsByOutcome**(collectionId: string,
8838
8858
  body: PublicInteractionsCountsByOutcomeRequest,
8839
8859
  authToken?: string) → `Promise<OutcomeCount[]>`
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`.
8860
+ 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
8861
 
8842
8862
  **publicMyInteractions**(collectionId: string,
8843
8863
  body: PublicInteractionsByUserRequest,
8844
8864
  authToken?: string) → `Promise<InteractionEventRow[]>`
8845
- 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`.
8865
+ 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`.
8846
8866
 
8847
8867
  **publicList**(collectionId: string,
8848
8868
  query: ListInteractionTypesQuery = {}) → `Promise<InteractionTypeList>`
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`.
8869
+ 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
8870
 
8851
8871
  **publicGet**(collectionId: string,
8852
8872
  id: string) → `Promise<InteractionTypeRecord>`
8853
- 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`.
8873
+ 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`.
8854
8874
 
8855
8875
  ### jobs
8856
8876
 
@@ -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,20 @@ 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 and/or a post-verification reply
92
+ // const wa = await authKit.sendWhatsApp(clientId, {
93
+ // redirectUrl: 'https://app.example.com/checkout/continue',
94
+ // reply: {
95
+ // cta: {
96
+ // body: "You're verified and ready to bid.",
97
+ // buttonLabel: 'Back to Auction',
98
+ // buttonUrl: '{{returnUrl}}',
99
+ // },
100
+ // text: "You're verified. Return to the app to continue.",
101
+ // },
102
+ // });
93
103
 
94
104
  // wa.waLink can be opened directly by the app/browser
95
105
  // Poll status while user switches to WhatsApp and back
@@ -133,6 +143,27 @@ Verification status values returned by `authKit.getWhatsAppStatus` are:
133
143
  - `expired`
134
144
  - `unknown`
135
145
 
146
+ #### Post-verification reply
147
+
148
+ Pass a `reply` object in `sendWhatsApp` to send a message back to the user after they confirm `CONFIRM <token>`. Reply resolution order:
149
+
150
+ 1. `reply.contentSid` — explicit Twilio Content SID
151
+ 2. `reply.cta` — CTA shorthand using the shared generic Twilio Content template SID (`TWILIO_WHATSAPP_GENERIC_CTA_SID`)
152
+ 3. `reply.text` — plain-text fallback
153
+ 4. Per-client default (`authKit/{clientId}.whatsapp` config)
154
+ 5. Built-in default text
155
+
156
+ The following template placeholders are available in `reply.text`, `reply.cta` fields, and `reply.contentVariables` values:
157
+
158
+ | Placeholder | Description |
159
+ |---|---|
160
+ | `{{returnUrl}}` | The resolved redirect URL |
161
+ | `{{phoneNumber}}` | The verified phone number |
162
+ | `{{clientId}}` | The Auth Kit client ID |
163
+ | `{{token}}` | The verification token |
164
+
165
+ > **Note:** `redirectUrl` is optional. WhatsApp tokens are short hex strings (16 chars) for better UX.
166
+
136
167
  ### Google OAuth
137
168
 
138
169
  ```ts
@@ -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
@@ -17864,6 +17864,31 @@ components:
17864
17864
  required:
17865
17865
  - success
17866
17866
  - message
17867
+ WhatsAppReplyCta:
17868
+ type: object
17869
+ properties:
17870
+ body:
17871
+ type: string
17872
+ buttonLabel:
17873
+ type: string
17874
+ buttonUrl:
17875
+ type: string
17876
+ required:
17877
+ - body
17878
+ - buttonLabel
17879
+ - buttonUrl
17880
+ WhatsAppReplyOptions:
17881
+ type: object
17882
+ properties:
17883
+ contentSid:
17884
+ type: string
17885
+ contentVariables:
17886
+ type: object
17887
+ additionalProperties: true
17888
+ cta:
17889
+ $ref: "#/components/schemas/WhatsAppReplyCta"
17890
+ text:
17891
+ type: string
17867
17892
  SendWhatsAppRequest:
17868
17893
  type: object
17869
17894
  properties:
@@ -17871,9 +17896,8 @@ components:
17871
17896
  type: string
17872
17897
  redirectUrl:
17873
17898
  type: string
17874
- required:
17875
- - phoneNumber
17876
- - redirectUrl
17899
+ reply:
17900
+ $ref: "#/components/schemas/WhatsAppReplyOptions"
17877
17901
  SendWhatsAppResponse:
17878
17902
  type: object
17879
17903
  properties:
@@ -76,9 +76,24 @@ export interface EmailVerifyTokenResponse {
76
76
  emailVerificationMode?: 'immediate' | 'verify-auto-login' | 'verify-manual-login';
77
77
  }
78
78
  export type VerifyStatus = 'pending' | 'verified' | 'failed' | 'expired' | 'unknown';
79
+ export interface WhatsAppReplyCta {
80
+ body: string;
81
+ buttonLabel: string;
82
+ buttonUrl: string;
83
+ }
84
+ export interface WhatsAppReplyOptions {
85
+ /** Option A: explicit Twilio Content SID */
86
+ contentSid?: string;
87
+ contentVariables?: Record<string, unknown>;
88
+ /** Option B: CTA shorthand (uses shared generic CTA content SID) */
89
+ cta?: WhatsAppReplyCta;
90
+ /** Option C: plain-text fallback */
91
+ text?: string;
92
+ }
79
93
  export interface SendWhatsAppRequest {
80
- phoneNumber: string;
81
- redirectUrl: string;
94
+ phoneNumber?: string;
95
+ redirectUrl?: string;
96
+ reply?: WhatsAppReplyOptions;
82
97
  }
83
98
  export interface SendWhatsAppResponse {
84
99
  waLink: string;
@@ -1,6 +1,6 @@
1
1
  # Smartlinks API Summary
2
2
 
3
- Version: 1.13.10 | Generated: 2026-05-12T16:12:33.784Z
3
+ Version: 1.13.12 | Generated: 2026-05-14T16:00:33.063Z
4
4
 
5
5
  This is a concise summary of all available API functions and types.
6
6
 
@@ -3024,11 +3024,31 @@ interface EmailVerifyTokenResponse {
3024
3024
  }
3025
3025
  ```
3026
3026
 
3027
+ **WhatsAppReplyCta** (interface)
3028
+ ```typescript
3029
+ interface WhatsAppReplyCta {
3030
+ body: string
3031
+ buttonLabel: string
3032
+ buttonUrl: string
3033
+ }
3034
+ ```
3035
+
3036
+ **WhatsAppReplyOptions** (interface)
3037
+ ```typescript
3038
+ interface WhatsAppReplyOptions {
3039
+ contentSid?: string
3040
+ contentVariables?: Record<string, unknown>
3041
+ cta?: WhatsAppReplyCta
3042
+ text?: string
3043
+ }
3044
+ ```
3045
+
3027
3046
  **SendWhatsAppRequest** (interface)
3028
3047
  ```typescript
3029
3048
  interface SendWhatsAppRequest {
3030
- phoneNumber: string
3031
- redirectUrl: string
3049
+ phoneNumber?: string
3050
+ redirectUrl?: string
3051
+ reply?: WhatsAppReplyOptions
3032
3052
  }
3033
3053
  ```
3034
3054
 
@@ -8192,7 +8212,7 @@ Send phone verification code (public).
8192
8212
  **verifyPhoneCode**(clientId: string, phoneNumber: string, code: string) → `Promise<PhoneVerifyResponse>`
8193
8213
  Verify phone verification code (public).
8194
8214
 
8195
- **sendWhatsApp**(clientId: string, body: SendWhatsAppRequest) → `Promise<SendWhatsAppResponse>`
8215
+ **sendWhatsApp**(clientId: string, body: SendWhatsAppRequest = {}) → `Promise<SendWhatsAppResponse>`
8196
8216
  Send a WhatsApp verification deep-link (public).
8197
8217
 
8198
8218
  **verifyWhatsApp**(clientId: string, token: string, phoneNumber: string) → `Promise<VerifyWhatsAppResponse>`
@@ -8803,54 +8823,54 @@ Legacy-friendly alias for aggregate().
8803
8823
 
8804
8824
  **appendEvent**(collectionId: string,
8805
8825
  body: AppendInteractionBody) → `Promise<`
8806
- POST /admin/collection/:collectionId/interactions/append Appends one interaction event.
8826
+ 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.
8807
8827
 
8808
8828
  **updateEvent**(collectionId: string,
8809
8829
  body: UpdateInteractionBody) → `Promise<`
8810
- POST /admin/collection/:collectionId/interactions/append Appends one interaction event.
8830
+ 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.
8811
8831
 
8812
8832
  **submitPublicEvent**(collectionId: string,
8813
8833
  body: AppendInteractionBody) → `Promise<SubmitInteractionResponse | SubmitInteractionError>`
8814
- 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`.
8834
+ 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`.
8815
8835
 
8816
8836
  **create**(collectionId: string,
8817
8837
  body: CreateInteractionTypeBody) → `Promise<InteractionTypeRecord>`
8818
- 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`.
8838
+ 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`.
8819
8839
 
8820
8840
  **list**(collectionId: string,
8821
8841
  query: ListInteractionTypesQuery = {}) → `Promise<InteractionTypeList>`
8822
- 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`.
8842
+ 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`.
8823
8843
 
8824
8844
  **get**(collectionId: string,
8825
8845
  id: string) → `Promise<InteractionTypeRecord>`
8826
- 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`.
8846
+ 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`.
8827
8847
 
8828
8848
  **update**(collectionId: string,
8829
8849
  id: string,
8830
8850
  patchBody: UpdateInteractionTypeBody) → `Promise<InteractionTypeRecord>`
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`.
8851
+ 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
8852
 
8833
8853
  **remove**(collectionId: string,
8834
8854
  id: string) → `Promise<void>`
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`.
8855
+ 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
8856
 
8837
8857
  **publicCountsByOutcome**(collectionId: string,
8838
8858
  body: PublicInteractionsCountsByOutcomeRequest,
8839
8859
  authToken?: string) → `Promise<OutcomeCount[]>`
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`.
8860
+ 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
8861
 
8842
8862
  **publicMyInteractions**(collectionId: string,
8843
8863
  body: PublicInteractionsByUserRequest,
8844
8864
  authToken?: string) → `Promise<InteractionEventRow[]>`
8845
- 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`.
8865
+ 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`.
8846
8866
 
8847
8867
  **publicList**(collectionId: string,
8848
8868
  query: ListInteractionTypesQuery = {}) → `Promise<InteractionTypeList>`
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`.
8869
+ 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
8870
 
8851
8871
  **publicGet**(collectionId: string,
8852
8872
  id: string) → `Promise<InteractionTypeRecord>`
8853
- 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`.
8873
+ 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`.
8854
8874
 
8855
8875
  ### jobs
8856
8876
 
@@ -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,20 @@ 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 and/or a post-verification reply
92
+ // const wa = await authKit.sendWhatsApp(clientId, {
93
+ // redirectUrl: 'https://app.example.com/checkout/continue',
94
+ // reply: {
95
+ // cta: {
96
+ // body: "You're verified and ready to bid.",
97
+ // buttonLabel: 'Back to Auction',
98
+ // buttonUrl: '{{returnUrl}}',
99
+ // },
100
+ // text: "You're verified. Return to the app to continue.",
101
+ // },
102
+ // });
93
103
 
94
104
  // wa.waLink can be opened directly by the app/browser
95
105
  // Poll status while user switches to WhatsApp and back
@@ -133,6 +143,27 @@ Verification status values returned by `authKit.getWhatsAppStatus` are:
133
143
  - `expired`
134
144
  - `unknown`
135
145
 
146
+ #### Post-verification reply
147
+
148
+ Pass a `reply` object in `sendWhatsApp` to send a message back to the user after they confirm `CONFIRM <token>`. Reply resolution order:
149
+
150
+ 1. `reply.contentSid` — explicit Twilio Content SID
151
+ 2. `reply.cta` — CTA shorthand using the shared generic Twilio Content template SID (`TWILIO_WHATSAPP_GENERIC_CTA_SID`)
152
+ 3. `reply.text` — plain-text fallback
153
+ 4. Per-client default (`authKit/{clientId}.whatsapp` config)
154
+ 5. Built-in default text
155
+
156
+ The following template placeholders are available in `reply.text`, `reply.cta` fields, and `reply.contentVariables` values:
157
+
158
+ | Placeholder | Description |
159
+ |---|---|
160
+ | `{{returnUrl}}` | The resolved redirect URL |
161
+ | `{{phoneNumber}}` | The verified phone number |
162
+ | `{{clientId}}` | The Auth Kit client ID |
163
+ | `{{token}}` | The verification token |
164
+
165
+ > **Note:** `redirectUrl` is optional. WhatsApp tokens are short hex strings (16 chars) for better UX.
166
+
136
167
  ### Google OAuth
137
168
 
138
169
  ```ts
@@ -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
@@ -17864,6 +17864,31 @@ components:
17864
17864
  required:
17865
17865
  - success
17866
17866
  - message
17867
+ WhatsAppReplyCta:
17868
+ type: object
17869
+ properties:
17870
+ body:
17871
+ type: string
17872
+ buttonLabel:
17873
+ type: string
17874
+ buttonUrl:
17875
+ type: string
17876
+ required:
17877
+ - body
17878
+ - buttonLabel
17879
+ - buttonUrl
17880
+ WhatsAppReplyOptions:
17881
+ type: object
17882
+ properties:
17883
+ contentSid:
17884
+ type: string
17885
+ contentVariables:
17886
+ type: object
17887
+ additionalProperties: true
17888
+ cta:
17889
+ $ref: "#/components/schemas/WhatsAppReplyCta"
17890
+ text:
17891
+ type: string
17867
17892
  SendWhatsAppRequest:
17868
17893
  type: object
17869
17894
  properties:
@@ -17871,9 +17896,8 @@ components:
17871
17896
  type: string
17872
17897
  redirectUrl:
17873
17898
  type: string
17874
- required:
17875
- - phoneNumber
17876
- - redirectUrl
17899
+ reply:
17900
+ $ref: "#/components/schemas/WhatsAppReplyOptions"
17877
17901
  SendWhatsAppResponse:
17878
17902
  type: object
17879
17903
  properties:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@proveanything/smartlinks",
3
- "version": "1.13.10",
3
+ "version": "1.13.12",
4
4
  "description": "Official JavaScript/TypeScript SDK for the Smartlinks API",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",