@kirimdev/sdk 3.1.1 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/openapi.json CHANGED
@@ -44,6 +44,10 @@
44
44
  "name": "Labels",
45
45
  "description": "Coloured tags for contacts and conversations. Team-scoped per Kirimdev's internal model."
46
46
  },
47
+ {
48
+ "name": "Customers",
49
+ "description": "End-customers (tenant-of-tenant) — your platform's own clients. Each Customer can connect their own WhatsApp accounts via setup links and you send messages on their behalf. Distinct from `Contacts`."
50
+ },
47
51
  {
48
52
  "name": "Webhook Subscriptions",
49
53
  "description": "Subscribe to events, rotate signing secrets, pause/resume delivery."
@@ -100,6 +104,50 @@
100
104
  "error"
101
105
  ]
102
106
  },
107
+ "WhatsappAccountEmbedded": {
108
+ "type": "object",
109
+ "properties": {
110
+ "phone_number": {
111
+ "type": [
112
+ "string",
113
+ "null"
114
+ ]
115
+ },
116
+ "phone_number_id": {
117
+ "type": [
118
+ "string",
119
+ "null"
120
+ ],
121
+ "example": "106540352242922",
122
+ "description": "Meta `business_phone_number_id` — use as the `{phone_number_id}` path segment in `/v1/{phone_number_id}/...` endpoints."
123
+ },
124
+ "customer": {
125
+ "type": [
126
+ "object",
127
+ "null"
128
+ ],
129
+ "properties": {
130
+ "id": {
131
+ "type": "string",
132
+ "example": "cus_01HXYZABCDEFGHJKMNPQRSTVWX"
133
+ },
134
+ "name": {
135
+ "type": "string"
136
+ }
137
+ },
138
+ "required": [
139
+ "id",
140
+ "name"
141
+ ],
142
+ "description": "End-customer (multi-tenant platform mode) that owns this account. NULL for direct-org accounts."
143
+ }
144
+ },
145
+ "required": [
146
+ "phone_number",
147
+ "phone_number_id",
148
+ "customer"
149
+ ]
150
+ },
103
151
  "Message": {
104
152
  "type": "object",
105
153
  "properties": {
@@ -145,7 +193,7 @@
145
193
  "properties": {
146
194
  "code": {
147
195
  "type": "string",
148
- "description": "Stable Kirim error code. Known values include `outside_24h_window`, `marketing_opted_out`, `marketing_blocked_by_user`, `recipient_unavailable`, `unsupported_message_type`, `account_restricted`, `account_locked`, `consent_required`, `permission_revoked`, `auth_expired`, `app_rate_limited`, `account_rate_limited`, `template_not_found`, `template_paused`, `template_policy_violation`, `flow_blocked`, `media_upload_failed`, `media_download_failed`, `undeliverable`, `policy_violation`, `upstream_error`."
196
+ "description": "Stable Kirim error code. Known values include `outside_24h_window`, `marketing_opted_out`, `marketing_blocked_by_user`, `recipient_unavailable`, `unsupported_message_type`, `account_restricted`, `account_locked`, `consent_required`, `customer_suspended`, `permission_revoked`, `auth_expired`, `app_rate_limited`, `account_rate_limited`, `template_not_found`, `template_paused`, `template_policy_violation`, `flow_blocked`, `media_upload_failed`, `media_download_failed`, `undeliverable`, `policy_violation`, `upstream_error`."
149
197
  },
150
198
  "message": {
151
199
  "type": "string"
@@ -208,18 +256,7 @@
208
256
  },
209
257
  "components": {},
210
258
  "whatsapp_account": {
211
- "type": "object",
212
- "properties": {
213
- "phone_number": {
214
- "type": [
215
- "string",
216
- "null"
217
- ]
218
- }
219
- },
220
- "required": [
221
- "phone_number"
222
- ]
259
+ "$ref": "#/components/schemas/WhatsappAccountEmbedded"
223
260
  },
224
261
  "provider_template_id": {
225
262
  "type": [
@@ -285,6 +322,14 @@
285
322
  "type": "string",
286
323
  "example": "connected",
287
324
  "description": "Lifecycle state of the account (e.g. `connected`, `disconnected`, `degraded`, `onboarding`)."
325
+ },
326
+ "customer_id": {
327
+ "type": [
328
+ "string",
329
+ "null"
330
+ ],
331
+ "example": "cus_01HXYZABCDEFGHJKMNPQRSTVWX",
332
+ "description": "Public id of the end-customer (multi-tenant platform mode) that owns this account. NULL for direct-org accounts. Filter the list endpoint via `?customer_id=cus_...`."
288
333
  }
289
334
  },
290
335
  "required": [
@@ -292,7 +337,8 @@
292
337
  "phone_number_id",
293
338
  "phone_number",
294
339
  "name",
295
- "status"
340
+ "status",
341
+ "customer_id"
296
342
  ]
297
343
  },
298
344
  "WebhookSubscription": {
@@ -539,18 +585,7 @@
539
585
  ]
540
586
  },
541
587
  "whatsapp_account": {
542
- "type": "object",
543
- "properties": {
544
- "phone_number": {
545
- "type": [
546
- "string",
547
- "null"
548
- ]
549
- }
550
- },
551
- "required": [
552
- "phone_number"
553
- ]
588
+ "$ref": "#/components/schemas/WhatsappAccountEmbedded"
554
589
  },
555
590
  "assignee": {
556
591
  "type": [
@@ -660,18 +695,7 @@
660
695
  "additionalProperties": {}
661
696
  },
662
697
  "whatsapp_account": {
663
- "type": "object",
664
- "properties": {
665
- "phone_number": {
666
- "type": [
667
- "string",
668
- "null"
669
- ]
670
- }
671
- },
672
- "required": [
673
- "phone_number"
674
- ]
698
+ "$ref": "#/components/schemas/WhatsappAccountEmbedded"
675
699
  },
676
700
  "created_at": {
677
701
  "type": "string",
@@ -750,6 +774,172 @@
750
774
  "updated_at"
751
775
  ]
752
776
  },
777
+ "Customer": {
778
+ "type": "object",
779
+ "properties": {
780
+ "id": {
781
+ "type": "string",
782
+ "example": "cus_01HXYZABCDEFGHJKMNPQRSTVWX"
783
+ },
784
+ "object": {
785
+ "type": "string",
786
+ "enum": [
787
+ "customer"
788
+ ]
789
+ },
790
+ "name": {
791
+ "type": "string"
792
+ },
793
+ "email": {
794
+ "type": [
795
+ "string",
796
+ "null"
797
+ ]
798
+ },
799
+ "status": {
800
+ "type": "string",
801
+ "enum": [
802
+ "pending",
803
+ "active",
804
+ "suspended",
805
+ "archived"
806
+ ]
807
+ },
808
+ "metadata": {
809
+ "type": [
810
+ "object",
811
+ "null"
812
+ ],
813
+ "additionalProperties": {}
814
+ },
815
+ "archived_at": {
816
+ "type": [
817
+ "string",
818
+ "null"
819
+ ],
820
+ "format": "date-time"
821
+ },
822
+ "team_id": {
823
+ "type": "string"
824
+ },
825
+ "created_at": {
826
+ "type": "string",
827
+ "format": "date-time"
828
+ },
829
+ "updated_at": {
830
+ "type": "string",
831
+ "format": "date-time"
832
+ }
833
+ },
834
+ "required": [
835
+ "id",
836
+ "object",
837
+ "name",
838
+ "email",
839
+ "status",
840
+ "metadata",
841
+ "archived_at",
842
+ "team_id",
843
+ "created_at",
844
+ "updated_at"
845
+ ]
846
+ },
847
+ "CustomerSetupLink": {
848
+ "type": "object",
849
+ "properties": {
850
+ "id": {
851
+ "type": "string",
852
+ "example": "csl_01HXYZABCDEFGHJKMNPQRSTVWX"
853
+ },
854
+ "object": {
855
+ "type": "string",
856
+ "enum": [
857
+ "customer_setup_link"
858
+ ]
859
+ },
860
+ "customer_id": {
861
+ "type": "string"
862
+ },
863
+ "status": {
864
+ "type": "string",
865
+ "enum": [
866
+ "active",
867
+ "consumed",
868
+ "expired",
869
+ "revoked"
870
+ ]
871
+ },
872
+ "token_last4": {
873
+ "type": "string"
874
+ },
875
+ "expires_at": {
876
+ "type": "string",
877
+ "format": "date-time"
878
+ },
879
+ "consumed_at": {
880
+ "type": [
881
+ "string",
882
+ "null"
883
+ ],
884
+ "format": "date-time"
885
+ },
886
+ "success_redirect_url": {
887
+ "type": [
888
+ "string",
889
+ "null"
890
+ ],
891
+ "format": "uri",
892
+ "description": "Where the tenant is redirected after successful Embedded Signup. We append `?customer_id=&account_id=&status=success` on the redirect."
893
+ },
894
+ "failure_redirect_url": {
895
+ "type": [
896
+ "string",
897
+ "null"
898
+ ],
899
+ "format": "uri",
900
+ "description": "Where the tenant is redirected on failure (link error, Meta signup cancelled, etc.). We append `?customer_id=&status=failed&reason=<code>`."
901
+ },
902
+ "created_at": {
903
+ "type": "string",
904
+ "format": "date-time"
905
+ }
906
+ },
907
+ "required": [
908
+ "id",
909
+ "object",
910
+ "customer_id",
911
+ "status",
912
+ "token_last4",
913
+ "expires_at",
914
+ "consumed_at",
915
+ "success_redirect_url",
916
+ "failure_redirect_url",
917
+ "created_at"
918
+ ]
919
+ },
920
+ "CustomerSetupLinkWithToken": {
921
+ "allOf": [
922
+ {
923
+ "$ref": "#/components/schemas/CustomerSetupLink"
924
+ },
925
+ {
926
+ "type": "object",
927
+ "properties": {
928
+ "setup_url": {
929
+ "type": "string",
930
+ "format": "uri"
931
+ },
932
+ "token": {
933
+ "type": "string"
934
+ }
935
+ },
936
+ "required": [
937
+ "setup_url",
938
+ "token"
939
+ ]
940
+ }
941
+ ]
942
+ },
753
943
  "MessageListItem": {
754
944
  "type": "object",
755
945
  "properties": {
@@ -813,7 +1003,7 @@
813
1003
  "properties": {
814
1004
  "code": {
815
1005
  "type": "string",
816
- "description": "Stable Kirim error code. Known values include `outside_24h_window`, `marketing_opted_out`, `marketing_blocked_by_user`, `recipient_unavailable`, `unsupported_message_type`, `account_restricted`, `account_locked`, `consent_required`, `permission_revoked`, `auth_expired`, `app_rate_limited`, `account_rate_limited`, `template_not_found`, `template_paused`, `template_policy_violation`, `flow_blocked`, `media_upload_failed`, `media_download_failed`, `undeliverable`, `policy_violation`, `upstream_error`."
1006
+ "description": "Stable Kirim error code. Known values include `outside_24h_window`, `marketing_opted_out`, `marketing_blocked_by_user`, `recipient_unavailable`, `unsupported_message_type`, `account_restricted`, `account_locked`, `consent_required`, `customer_suspended`, `permission_revoked`, `auth_expired`, `app_rate_limited`, `account_rate_limited`, `template_not_found`, `template_paused`, `template_policy_violation`, `flow_blocked`, `media_upload_failed`, `media_download_failed`, `undeliverable`, `policy_violation`, `upstream_error`."
817
1007
  },
818
1008
  "message": {
819
1009
  "type": "string"
@@ -1039,6 +1229,47 @@
1039
1229
  "request_id"
1040
1230
  ]
1041
1231
  },
1232
+ "SyncTemplatesResponse": {
1233
+ "type": "object",
1234
+ "properties": {
1235
+ "data": {
1236
+ "type": "object",
1237
+ "properties": {
1238
+ "object": {
1239
+ "type": "string",
1240
+ "enum": [
1241
+ "template_sync_result"
1242
+ ]
1243
+ },
1244
+ "synced": {
1245
+ "type": "integer",
1246
+ "example": 12
1247
+ },
1248
+ "created": {
1249
+ "type": "integer",
1250
+ "example": 2
1251
+ },
1252
+ "updated": {
1253
+ "type": "integer",
1254
+ "example": 10
1255
+ }
1256
+ },
1257
+ "required": [
1258
+ "object",
1259
+ "synced",
1260
+ "created",
1261
+ "updated"
1262
+ ]
1263
+ },
1264
+ "request_id": {
1265
+ "type": "string"
1266
+ }
1267
+ },
1268
+ "required": [
1269
+ "data",
1270
+ "request_id"
1271
+ ]
1272
+ },
1042
1273
  "CreateWebhookSubscriptionResponse": {
1043
1274
  "type": "object",
1044
1275
  "properties": {
@@ -1812,23 +2043,296 @@
1812
2043
  "data",
1813
2044
  "request_id"
1814
2045
  ]
1815
- }
1816
- },
1817
- "parameters": {}
1818
- },
1819
- "paths": {
1820
- "/health": {
1821
- "get": {
1822
- "tags": [
1823
- "Meta"
1824
- ],
1825
- "summary": "Liveness probe",
1826
- "description": "Unauthenticated health check. Returns 200 if the API is up.",
1827
- "responses": {
1828
- "200": {
1829
- "description": "API is healthy",
1830
- "content": {
1831
- "application/json": {
2046
+ },
2047
+ "ListCustomersResponse": {
2048
+ "type": "object",
2049
+ "properties": {
2050
+ "data": {
2051
+ "type": "array",
2052
+ "items": {
2053
+ "$ref": "#/components/schemas/Customer"
2054
+ }
2055
+ },
2056
+ "has_more": {
2057
+ "type": "boolean"
2058
+ },
2059
+ "next_cursor": {
2060
+ "type": [
2061
+ "string",
2062
+ "null"
2063
+ ]
2064
+ },
2065
+ "request_id": {
2066
+ "type": "string"
2067
+ }
2068
+ },
2069
+ "required": [
2070
+ "data",
2071
+ "has_more",
2072
+ "next_cursor",
2073
+ "request_id"
2074
+ ]
2075
+ },
2076
+ "CreateCustomerResponse": {
2077
+ "type": "object",
2078
+ "properties": {
2079
+ "data": {
2080
+ "$ref": "#/components/schemas/Customer"
2081
+ },
2082
+ "request_id": {
2083
+ "type": "string"
2084
+ }
2085
+ },
2086
+ "required": [
2087
+ "data",
2088
+ "request_id"
2089
+ ]
2090
+ },
2091
+ "GetCustomerResponse": {
2092
+ "type": "object",
2093
+ "properties": {
2094
+ "data": {
2095
+ "allOf": [
2096
+ {
2097
+ "$ref": "#/components/schemas/Customer"
2098
+ },
2099
+ {
2100
+ "type": "object",
2101
+ "properties": {
2102
+ "whatsapp_accounts": {
2103
+ "type": "array",
2104
+ "items": {
2105
+ "type": "object",
2106
+ "properties": {
2107
+ "phone_number_id": {
2108
+ "type": [
2109
+ "string",
2110
+ "null"
2111
+ ]
2112
+ },
2113
+ "phone_number": {
2114
+ "type": [
2115
+ "string",
2116
+ "null"
2117
+ ]
2118
+ },
2119
+ "name": {
2120
+ "type": [
2121
+ "string",
2122
+ "null"
2123
+ ]
2124
+ },
2125
+ "status": {
2126
+ "type": "string"
2127
+ },
2128
+ "onboarded_at": {
2129
+ "type": [
2130
+ "string",
2131
+ "null"
2132
+ ],
2133
+ "format": "date-time"
2134
+ }
2135
+ },
2136
+ "required": [
2137
+ "phone_number_id",
2138
+ "phone_number",
2139
+ "name",
2140
+ "status",
2141
+ "onboarded_at"
2142
+ ]
2143
+ },
2144
+ "description": "WhatsApp accounts currently assigned to this customer."
2145
+ }
2146
+ },
2147
+ "required": [
2148
+ "whatsapp_accounts"
2149
+ ]
2150
+ }
2151
+ ]
2152
+ },
2153
+ "request_id": {
2154
+ "type": "string"
2155
+ }
2156
+ },
2157
+ "required": [
2158
+ "data",
2159
+ "request_id"
2160
+ ]
2161
+ },
2162
+ "UpdateCustomerResponse": {
2163
+ "type": "object",
2164
+ "properties": {
2165
+ "data": {
2166
+ "$ref": "#/components/schemas/Customer"
2167
+ },
2168
+ "request_id": {
2169
+ "type": "string"
2170
+ }
2171
+ },
2172
+ "required": [
2173
+ "data",
2174
+ "request_id"
2175
+ ]
2176
+ },
2177
+ "ArchiveCustomerResponse": {
2178
+ "type": "object",
2179
+ "properties": {
2180
+ "data": {
2181
+ "type": "object",
2182
+ "properties": {
2183
+ "id": {
2184
+ "type": "string"
2185
+ },
2186
+ "object": {
2187
+ "type": "string",
2188
+ "enum": [
2189
+ "customer"
2190
+ ]
2191
+ },
2192
+ "archived": {
2193
+ "type": "boolean",
2194
+ "enum": [
2195
+ true
2196
+ ]
2197
+ }
2198
+ },
2199
+ "required": [
2200
+ "id",
2201
+ "object",
2202
+ "archived"
2203
+ ]
2204
+ },
2205
+ "request_id": {
2206
+ "type": "string"
2207
+ }
2208
+ },
2209
+ "required": [
2210
+ "data",
2211
+ "request_id"
2212
+ ]
2213
+ },
2214
+ "ListCustomerSetupLinksResponse": {
2215
+ "type": "object",
2216
+ "properties": {
2217
+ "data": {
2218
+ "type": "array",
2219
+ "items": {
2220
+ "$ref": "#/components/schemas/CustomerSetupLink"
2221
+ }
2222
+ },
2223
+ "has_more": {
2224
+ "type": "boolean"
2225
+ },
2226
+ "next_cursor": {
2227
+ "type": [
2228
+ "string",
2229
+ "null"
2230
+ ]
2231
+ },
2232
+ "request_id": {
2233
+ "type": "string"
2234
+ }
2235
+ },
2236
+ "required": [
2237
+ "data",
2238
+ "has_more",
2239
+ "next_cursor",
2240
+ "request_id"
2241
+ ]
2242
+ },
2243
+ "CreateCustomerSetupLinkResponse": {
2244
+ "type": "object",
2245
+ "properties": {
2246
+ "data": {
2247
+ "$ref": "#/components/schemas/CustomerSetupLinkWithToken"
2248
+ },
2249
+ "request_id": {
2250
+ "type": "string"
2251
+ }
2252
+ },
2253
+ "required": [
2254
+ "data",
2255
+ "request_id"
2256
+ ]
2257
+ },
2258
+ "UpdateCustomerSetupLinkResponse": {
2259
+ "type": "object",
2260
+ "properties": {
2261
+ "data": {
2262
+ "$ref": "#/components/schemas/CustomerSetupLink"
2263
+ },
2264
+ "request_id": {
2265
+ "type": "string"
2266
+ }
2267
+ },
2268
+ "required": [
2269
+ "data",
2270
+ "request_id"
2271
+ ]
2272
+ },
2273
+ "RevokeCustomerSetupLinkResponse": {
2274
+ "type": "object",
2275
+ "properties": {
2276
+ "data": {
2277
+ "type": "object",
2278
+ "properties": {
2279
+ "id": {
2280
+ "type": "string"
2281
+ },
2282
+ "object": {
2283
+ "type": "string",
2284
+ "enum": [
2285
+ "customer_setup_link"
2286
+ ]
2287
+ },
2288
+ "revoked": {
2289
+ "type": "boolean",
2290
+ "enum": [
2291
+ true
2292
+ ]
2293
+ },
2294
+ "status": {
2295
+ "type": "string",
2296
+ "enum": [
2297
+ "active",
2298
+ "consumed",
2299
+ "expired",
2300
+ "revoked"
2301
+ ]
2302
+ }
2303
+ },
2304
+ "required": [
2305
+ "id",
2306
+ "object",
2307
+ "revoked",
2308
+ "status"
2309
+ ]
2310
+ },
2311
+ "request_id": {
2312
+ "type": "string"
2313
+ }
2314
+ },
2315
+ "required": [
2316
+ "data",
2317
+ "request_id"
2318
+ ]
2319
+ }
2320
+ },
2321
+ "parameters": {}
2322
+ },
2323
+ "paths": {
2324
+ "/health": {
2325
+ "get": {
2326
+ "tags": [
2327
+ "Meta"
2328
+ ],
2329
+ "summary": "Liveness probe",
2330
+ "description": "Unauthenticated health check. Returns 200 if the API is up.",
2331
+ "responses": {
2332
+ "200": {
2333
+ "description": "API is healthy",
2334
+ "content": {
2335
+ "application/json": {
1832
2336
  "schema": {
1833
2337
  "type": "object",
1834
2338
  "properties": {
@@ -1941,6 +2445,15 @@
1941
2445
  "required": false,
1942
2446
  "name": "status",
1943
2447
  "in": "query"
2448
+ },
2449
+ {
2450
+ "schema": {
2451
+ "type": "string",
2452
+ "pattern": "^cus_[0-9A-HJKMNP-TV-Z]{26}$"
2453
+ },
2454
+ "required": false,
2455
+ "name": "customer_id",
2456
+ "in": "query"
1944
2457
  }
1945
2458
  ],
1946
2459
  "responses": {
@@ -2003,7 +2516,7 @@
2003
2516
  "Messages"
2004
2517
  ],
2005
2518
  "summary": "Send a WhatsApp message or mark inbound as read",
2006
- "description": "Meta-style messages endpoint. Two operations share the same path, distinguished by the request body:\n\n**Outbound send** — body has a `type` field (`text`, `image`, `document`, `video`, `audio`, `template`, `interactive`). Body shape mirrors the Meta WhatsApp Cloud API; media variants accept either `link` (hosted URL) or `id` (Meta uploaded media). The sender is the WhatsApp account identified by `phone_number_id` in the URL path; there is no `from` field in the body. Pass `Idempotency-Key` to safely retry on network failure.\n\n**Read receipt** — body has `status: \"read\"` + `message_id` (the inbound wamid from your webhook). Sends a read receipt back to the sender so the double-tick turns blue on their phone. Optional `typing_indicator: { type: \"text\" }` shows a typing bubble alongside the receipt; Meta auto-dismisses after ~25 seconds or on first outbound message.\n\n**Pre-send validation** — the API performs compliance checks before queuing the send. A 422 response with `error.code` set to `marketing_opted_out` indicates the recipient has stopped marketing messages from your business (the customer did this via the WhatsApp app menu — webhook `user_preferences` notifies you of the change). `account_restricted` indicates Meta has restricted your WhatsApp account; check the account status via the dashboard. `consent_required` indicates the recipient has not opted in. `upstream_error` indicates the WhatsApp account is disconnected. None of these are retryable until the underlying condition changes.",
2519
+ "description": "Meta-style messages endpoint. Two operations share the same path, distinguished by the request body:\n\n**Outbound send** — body has a `type` field (`text`, `image`, `document`, `video`, `audio`, `template`, `interactive`). Body shape mirrors the Meta WhatsApp Cloud API; media variants accept either `link` (hosted URL) or `id` (Meta uploaded media). The sender is the WhatsApp account identified by `phone_number_id` in the URL path; there is no `from` field in the body. Pass `Idempotency-Key` to safely retry on network failure.\n\n**Read receipt** — body has `status: \"read\"` + `message_id` (the inbound wamid from your webhook). Sends a read receipt back to the sender so the double-tick turns blue on their phone. Optional `typing_indicator: { type: \"text\" }` shows a typing bubble alongside the receipt; Meta auto-dismisses after ~25 seconds or on first outbound message.\n\n**Pre-send validation** — the API performs compliance checks before queuing the send. A 422 response with `error.code` set to `marketing_opted_out` indicates the recipient has stopped marketing messages from your business (the customer did this via the WhatsApp app menu — webhook `user_preferences` notifies you of the change). `account_restricted` indicates Meta has restricted your WhatsApp account; check the account status via the dashboard. `consent_required` indicates the recipient has not opted in. `customer_suspended` indicates the operator has suspended (or archived) the customer that owns this WhatsApp account; sends are blocked until the customer is unsuspended via the dashboard. `upstream_error` indicates the WhatsApp account is disconnected. None of these are retryable until the underlying condition changes.",
2007
2520
  "security": [
2008
2521
  {
2009
2522
  "bearerAuth": []
@@ -3729,28 +4242,138 @@
3729
4242
  }
3730
4243
  }
3731
4244
  },
3732
- "/webhook_subscriptions": {
4245
+ "/{phone_number_id}/templates/sync": {
3733
4246
  "post": {
3734
4247
  "tags": [
3735
- "Webhook Subscriptions"
4248
+ "Templates"
3736
4249
  ],
3737
- "summary": "Create a webhook subscription",
3738
- "description": "Create a webhook subscription. The response carries `initial_secret` ONCE store it server-side immediately; Kirimdev cannot show it again.",
4250
+ "summary": "Sync templates from Meta",
4251
+ "description": "Pull the latest template inventory from Meta and upsert into the Kirim DB for this WhatsApp account. Idempotent call any time, returns a `{ created, updated, synced }` summary. Useful for platform integrations (multi-tenant Customers) so they don't need to wait for an operator to click \"Sync\" in the dashboard.",
3739
4252
  "security": [
3740
4253
  {
3741
4254
  "bearerAuth": []
3742
4255
  }
3743
4256
  ],
3744
- "requestBody": {
3745
- "content": {
3746
- "application/json": {
3747
- "schema": {
3748
- "type": "object",
3749
- "properties": {
3750
- "url": {
3751
- "type": "string",
3752
- "format": "uri"
3753
- },
4257
+ "parameters": [
4258
+ {
4259
+ "schema": {
4260
+ "type": "string",
4261
+ "pattern": "^\\d{6,20}$",
4262
+ "example": "106540352242922",
4263
+ "description": "Meta WhatsApp Business `phone_number_id` of the connected account that should send / own this resource. Discoverable via `GET /v1/accounts` (returned as `phone_number_id` on each row)."
4264
+ },
4265
+ "required": true,
4266
+ "description": "Meta WhatsApp Business `phone_number_id` of the connected account that should send / own this resource. Discoverable via `GET /v1/accounts` (returned as `phone_number_id` on each row).",
4267
+ "name": "phone_number_id",
4268
+ "in": "path"
4269
+ }
4270
+ ],
4271
+ "responses": {
4272
+ "200": {
4273
+ "description": "Sync summary",
4274
+ "content": {
4275
+ "application/json": {
4276
+ "schema": {
4277
+ "$ref": "#/components/schemas/SyncTemplatesResponse"
4278
+ }
4279
+ }
4280
+ }
4281
+ },
4282
+ "400": {
4283
+ "description": "Validation failure",
4284
+ "content": {
4285
+ "application/json": {
4286
+ "schema": {
4287
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
4288
+ }
4289
+ }
4290
+ }
4291
+ },
4292
+ "401": {
4293
+ "description": "Authentication failure",
4294
+ "content": {
4295
+ "application/json": {
4296
+ "schema": {
4297
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
4298
+ }
4299
+ }
4300
+ }
4301
+ },
4302
+ "404": {
4303
+ "description": "Resource not found",
4304
+ "content": {
4305
+ "application/json": {
4306
+ "schema": {
4307
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
4308
+ }
4309
+ }
4310
+ }
4311
+ },
4312
+ "422": {
4313
+ "description": "Semantic failure (e.g. idempotency key reuse)",
4314
+ "content": {
4315
+ "application/json": {
4316
+ "schema": {
4317
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
4318
+ }
4319
+ }
4320
+ }
4321
+ },
4322
+ "429": {
4323
+ "description": "Rate limit exceeded",
4324
+ "content": {
4325
+ "application/json": {
4326
+ "schema": {
4327
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
4328
+ }
4329
+ }
4330
+ }
4331
+ },
4332
+ "500": {
4333
+ "description": "Internal server error",
4334
+ "content": {
4335
+ "application/json": {
4336
+ "schema": {
4337
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
4338
+ }
4339
+ }
4340
+ }
4341
+ },
4342
+ "502": {
4343
+ "description": "Upstream WhatsApp error",
4344
+ "content": {
4345
+ "application/json": {
4346
+ "schema": {
4347
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
4348
+ }
4349
+ }
4350
+ }
4351
+ }
4352
+ }
4353
+ }
4354
+ },
4355
+ "/webhook_subscriptions": {
4356
+ "post": {
4357
+ "tags": [
4358
+ "Webhook Subscriptions"
4359
+ ],
4360
+ "summary": "Create a webhook subscription",
4361
+ "description": "Create a webhook subscription. The response carries `initial_secret` ONCE — store it server-side immediately; Kirimdev cannot show it again.",
4362
+ "security": [
4363
+ {
4364
+ "bearerAuth": []
4365
+ }
4366
+ ],
4367
+ "requestBody": {
4368
+ "content": {
4369
+ "application/json": {
4370
+ "schema": {
4371
+ "type": "object",
4372
+ "properties": {
4373
+ "url": {
4374
+ "type": "string",
4375
+ "format": "uri"
4376
+ },
3754
4377
  "description": {
3755
4378
  "type": "string",
3756
4379
  "maxLength": 200
@@ -3765,7 +4388,13 @@
3765
4388
  "conversation.assigned",
3766
4389
  "conversation.closed",
3767
4390
  "contact.created",
3768
- "contact.updated"
4391
+ "contact.updated",
4392
+ "customer.created",
4393
+ "customer.updated",
4394
+ "customer.archived",
4395
+ "customer.onboarded",
4396
+ "customer.setup_link.created",
4397
+ "customer.setup_link.consumed"
3769
4398
  ]
3770
4399
  },
3771
4400
  "minItems": 1
@@ -4073,7 +4702,13 @@
4073
4702
  "conversation.assigned",
4074
4703
  "conversation.closed",
4075
4704
  "contact.created",
4076
- "contact.updated"
4705
+ "contact.updated",
4706
+ "customer.created",
4707
+ "customer.updated",
4708
+ "customer.archived",
4709
+ "customer.onboarded",
4710
+ "customer.setup_link.created",
4711
+ "customer.setup_link.consumed"
4077
4712
  ]
4078
4713
  },
4079
4714
  "minItems": 1
@@ -7136,6 +7771,963 @@
7136
7771
  }
7137
7772
  }
7138
7773
  }
7774
+ },
7775
+ "/customers": {
7776
+ "get": {
7777
+ "tags": [
7778
+ "Customers"
7779
+ ],
7780
+ "summary": "List customers",
7781
+ "description": "List end-customers (tenant-of-tenant) attached to the organization. Each customer can own one or more WhatsApp accounts via setup links. NOTE: a customer here is NOT a WhatsApp contact — see the `/{phone_number_id}/contacts` resource for those.",
7782
+ "security": [
7783
+ {
7784
+ "bearerAuth": []
7785
+ }
7786
+ ],
7787
+ "parameters": [
7788
+ {
7789
+ "schema": {
7790
+ "type": "string",
7791
+ "enum": [
7792
+ "pending",
7793
+ "active",
7794
+ "suspended",
7795
+ "archived"
7796
+ ]
7797
+ },
7798
+ "required": false,
7799
+ "name": "status",
7800
+ "in": "query"
7801
+ },
7802
+ {
7803
+ "schema": {
7804
+ "type": "string",
7805
+ "minLength": 1,
7806
+ "maxLength": 200
7807
+ },
7808
+ "required": false,
7809
+ "name": "search",
7810
+ "in": "query"
7811
+ },
7812
+ {
7813
+ "schema": {
7814
+ "type": "string",
7815
+ "pattern": "^\\d+$"
7816
+ },
7817
+ "required": false,
7818
+ "name": "limit",
7819
+ "in": "query"
7820
+ },
7821
+ {
7822
+ "schema": {
7823
+ "type": "string"
7824
+ },
7825
+ "required": false,
7826
+ "name": "cursor",
7827
+ "in": "query"
7828
+ }
7829
+ ],
7830
+ "responses": {
7831
+ "200": {
7832
+ "description": "Customer list",
7833
+ "content": {
7834
+ "application/json": {
7835
+ "schema": {
7836
+ "$ref": "#/components/schemas/ListCustomersResponse"
7837
+ }
7838
+ }
7839
+ }
7840
+ },
7841
+ "400": {
7842
+ "description": "Validation failure",
7843
+ "content": {
7844
+ "application/json": {
7845
+ "schema": {
7846
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
7847
+ }
7848
+ }
7849
+ }
7850
+ },
7851
+ "401": {
7852
+ "description": "Authentication failure",
7853
+ "content": {
7854
+ "application/json": {
7855
+ "schema": {
7856
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
7857
+ }
7858
+ }
7859
+ }
7860
+ },
7861
+ "429": {
7862
+ "description": "Rate limit exceeded",
7863
+ "content": {
7864
+ "application/json": {
7865
+ "schema": {
7866
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
7867
+ }
7868
+ }
7869
+ }
7870
+ },
7871
+ "500": {
7872
+ "description": "Internal server error",
7873
+ "content": {
7874
+ "application/json": {
7875
+ "schema": {
7876
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
7877
+ }
7878
+ }
7879
+ }
7880
+ }
7881
+ }
7882
+ },
7883
+ "post": {
7884
+ "tags": [
7885
+ "Customers"
7886
+ ],
7887
+ "summary": "Create a customer",
7888
+ "description": "Create a new end-customer. Starts in `pending` status; transitions to `active` when the first WhatsApp account is connected via a setup link.",
7889
+ "security": [
7890
+ {
7891
+ "bearerAuth": []
7892
+ }
7893
+ ],
7894
+ "requestBody": {
7895
+ "content": {
7896
+ "application/json": {
7897
+ "schema": {
7898
+ "type": "object",
7899
+ "properties": {
7900
+ "team_id": {
7901
+ "type": "string",
7902
+ "minLength": 1,
7903
+ "maxLength": 64
7904
+ },
7905
+ "name": {
7906
+ "type": "string",
7907
+ "minLength": 1,
7908
+ "maxLength": 200
7909
+ },
7910
+ "email": {
7911
+ "type": "string",
7912
+ "maxLength": 255,
7913
+ "format": "email"
7914
+ },
7915
+ "metadata": {
7916
+ "type": "object",
7917
+ "additionalProperties": {}
7918
+ }
7919
+ },
7920
+ "required": [
7921
+ "name"
7922
+ ]
7923
+ }
7924
+ }
7925
+ }
7926
+ },
7927
+ "responses": {
7928
+ "200": {
7929
+ "description": "Customer created",
7930
+ "content": {
7931
+ "application/json": {
7932
+ "schema": {
7933
+ "$ref": "#/components/schemas/CreateCustomerResponse"
7934
+ }
7935
+ }
7936
+ }
7937
+ },
7938
+ "400": {
7939
+ "description": "Validation failure",
7940
+ "content": {
7941
+ "application/json": {
7942
+ "schema": {
7943
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
7944
+ }
7945
+ }
7946
+ }
7947
+ },
7948
+ "401": {
7949
+ "description": "Authentication failure",
7950
+ "content": {
7951
+ "application/json": {
7952
+ "schema": {
7953
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
7954
+ }
7955
+ }
7956
+ }
7957
+ },
7958
+ "429": {
7959
+ "description": "Rate limit exceeded",
7960
+ "content": {
7961
+ "application/json": {
7962
+ "schema": {
7963
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
7964
+ }
7965
+ }
7966
+ }
7967
+ },
7968
+ "500": {
7969
+ "description": "Internal server error",
7970
+ "content": {
7971
+ "application/json": {
7972
+ "schema": {
7973
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
7974
+ }
7975
+ }
7976
+ }
7977
+ }
7978
+ }
7979
+ }
7980
+ },
7981
+ "/customers/{id}": {
7982
+ "get": {
7983
+ "tags": [
7984
+ "Customers"
7985
+ ],
7986
+ "summary": "Fetch a customer by id",
7987
+ "security": [
7988
+ {
7989
+ "bearerAuth": []
7990
+ }
7991
+ ],
7992
+ "parameters": [
7993
+ {
7994
+ "schema": {
7995
+ "type": "string",
7996
+ "pattern": "^cus_[0-9A-HJKMNP-TV-Z]{26}$"
7997
+ },
7998
+ "required": true,
7999
+ "name": "id",
8000
+ "in": "path"
8001
+ }
8002
+ ],
8003
+ "responses": {
8004
+ "200": {
8005
+ "description": "Customer resource (includes attached WhatsApp accounts)",
8006
+ "content": {
8007
+ "application/json": {
8008
+ "schema": {
8009
+ "$ref": "#/components/schemas/GetCustomerResponse"
8010
+ }
8011
+ }
8012
+ }
8013
+ },
8014
+ "400": {
8015
+ "description": "Validation failure",
8016
+ "content": {
8017
+ "application/json": {
8018
+ "schema": {
8019
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
8020
+ }
8021
+ }
8022
+ }
8023
+ },
8024
+ "401": {
8025
+ "description": "Authentication failure",
8026
+ "content": {
8027
+ "application/json": {
8028
+ "schema": {
8029
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
8030
+ }
8031
+ }
8032
+ }
8033
+ },
8034
+ "404": {
8035
+ "description": "Resource not found",
8036
+ "content": {
8037
+ "application/json": {
8038
+ "schema": {
8039
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
8040
+ }
8041
+ }
8042
+ }
8043
+ },
8044
+ "429": {
8045
+ "description": "Rate limit exceeded",
8046
+ "content": {
8047
+ "application/json": {
8048
+ "schema": {
8049
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
8050
+ }
8051
+ }
8052
+ }
8053
+ },
8054
+ "500": {
8055
+ "description": "Internal server error",
8056
+ "content": {
8057
+ "application/json": {
8058
+ "schema": {
8059
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
8060
+ }
8061
+ }
8062
+ }
8063
+ }
8064
+ }
8065
+ },
8066
+ "patch": {
8067
+ "tags": [
8068
+ "Customers"
8069
+ ],
8070
+ "summary": "Update a customer",
8071
+ "security": [
8072
+ {
8073
+ "bearerAuth": []
8074
+ }
8075
+ ],
8076
+ "parameters": [
8077
+ {
8078
+ "schema": {
8079
+ "type": "string",
8080
+ "pattern": "^cus_[0-9A-HJKMNP-TV-Z]{26}$"
8081
+ },
8082
+ "required": true,
8083
+ "name": "id",
8084
+ "in": "path"
8085
+ }
8086
+ ],
8087
+ "requestBody": {
8088
+ "content": {
8089
+ "application/json": {
8090
+ "schema": {
8091
+ "type": "object",
8092
+ "properties": {
8093
+ "name": {
8094
+ "type": "string",
8095
+ "minLength": 1,
8096
+ "maxLength": 200
8097
+ },
8098
+ "email": {
8099
+ "type": [
8100
+ "string",
8101
+ "null"
8102
+ ],
8103
+ "maxLength": 255,
8104
+ "format": "email"
8105
+ },
8106
+ "metadata": {
8107
+ "type": [
8108
+ "object",
8109
+ "null"
8110
+ ],
8111
+ "additionalProperties": {}
8112
+ },
8113
+ "status": {
8114
+ "type": "string",
8115
+ "enum": [
8116
+ "pending",
8117
+ "active",
8118
+ "suspended"
8119
+ ]
8120
+ }
8121
+ }
8122
+ }
8123
+ }
8124
+ }
8125
+ },
8126
+ "responses": {
8127
+ "200": {
8128
+ "description": "Updated customer",
8129
+ "content": {
8130
+ "application/json": {
8131
+ "schema": {
8132
+ "$ref": "#/components/schemas/UpdateCustomerResponse"
8133
+ }
8134
+ }
8135
+ }
8136
+ },
8137
+ "400": {
8138
+ "description": "Validation failure",
8139
+ "content": {
8140
+ "application/json": {
8141
+ "schema": {
8142
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
8143
+ }
8144
+ }
8145
+ }
8146
+ },
8147
+ "401": {
8148
+ "description": "Authentication failure",
8149
+ "content": {
8150
+ "application/json": {
8151
+ "schema": {
8152
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
8153
+ }
8154
+ }
8155
+ }
8156
+ },
8157
+ "404": {
8158
+ "description": "Resource not found",
8159
+ "content": {
8160
+ "application/json": {
8161
+ "schema": {
8162
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
8163
+ }
8164
+ }
8165
+ }
8166
+ },
8167
+ "429": {
8168
+ "description": "Rate limit exceeded",
8169
+ "content": {
8170
+ "application/json": {
8171
+ "schema": {
8172
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
8173
+ }
8174
+ }
8175
+ }
8176
+ },
8177
+ "500": {
8178
+ "description": "Internal server error",
8179
+ "content": {
8180
+ "application/json": {
8181
+ "schema": {
8182
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
8183
+ }
8184
+ }
8185
+ }
8186
+ }
8187
+ }
8188
+ },
8189
+ "delete": {
8190
+ "tags": [
8191
+ "Customers"
8192
+ ],
8193
+ "summary": "Archive a customer",
8194
+ "description": "Soft-archives the customer. WhatsApp accounts previously assigned remain in the database with `customer_id` unchanged — message history is never destroyed.",
8195
+ "security": [
8196
+ {
8197
+ "bearerAuth": []
8198
+ }
8199
+ ],
8200
+ "parameters": [
8201
+ {
8202
+ "schema": {
8203
+ "type": "string",
8204
+ "pattern": "^cus_[0-9A-HJKMNP-TV-Z]{26}$"
8205
+ },
8206
+ "required": true,
8207
+ "name": "id",
8208
+ "in": "path"
8209
+ }
8210
+ ],
8211
+ "responses": {
8212
+ "200": {
8213
+ "description": "Archived",
8214
+ "content": {
8215
+ "application/json": {
8216
+ "schema": {
8217
+ "$ref": "#/components/schemas/ArchiveCustomerResponse"
8218
+ }
8219
+ }
8220
+ }
8221
+ },
8222
+ "400": {
8223
+ "description": "Validation failure",
8224
+ "content": {
8225
+ "application/json": {
8226
+ "schema": {
8227
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
8228
+ }
8229
+ }
8230
+ }
8231
+ },
8232
+ "401": {
8233
+ "description": "Authentication failure",
8234
+ "content": {
8235
+ "application/json": {
8236
+ "schema": {
8237
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
8238
+ }
8239
+ }
8240
+ }
8241
+ },
8242
+ "404": {
8243
+ "description": "Resource not found",
8244
+ "content": {
8245
+ "application/json": {
8246
+ "schema": {
8247
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
8248
+ }
8249
+ }
8250
+ }
8251
+ },
8252
+ "429": {
8253
+ "description": "Rate limit exceeded",
8254
+ "content": {
8255
+ "application/json": {
8256
+ "schema": {
8257
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
8258
+ }
8259
+ }
8260
+ }
8261
+ },
8262
+ "500": {
8263
+ "description": "Internal server error",
8264
+ "content": {
8265
+ "application/json": {
8266
+ "schema": {
8267
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
8268
+ }
8269
+ }
8270
+ }
8271
+ }
8272
+ }
8273
+ }
8274
+ },
8275
+ "/customers/{id}/setup_links": {
8276
+ "get": {
8277
+ "tags": [
8278
+ "Customers"
8279
+ ],
8280
+ "summary": "List setup links for a customer",
8281
+ "description": "Returns up to the 50 most-recent setup links — token plaintext is NEVER returned here (only at create time). Optional `status` query filters to `active` / `consumed` / `expired` / `revoked`.",
8282
+ "security": [
8283
+ {
8284
+ "bearerAuth": []
8285
+ }
8286
+ ],
8287
+ "parameters": [
8288
+ {
8289
+ "schema": {
8290
+ "type": "string",
8291
+ "pattern": "^cus_[0-9A-HJKMNP-TV-Z]{26}$"
8292
+ },
8293
+ "required": true,
8294
+ "name": "id",
8295
+ "in": "path"
8296
+ },
8297
+ {
8298
+ "schema": {
8299
+ "type": "string",
8300
+ "enum": [
8301
+ "active",
8302
+ "consumed",
8303
+ "expired",
8304
+ "revoked"
8305
+ ]
8306
+ },
8307
+ "required": false,
8308
+ "name": "status",
8309
+ "in": "query"
8310
+ }
8311
+ ],
8312
+ "responses": {
8313
+ "200": {
8314
+ "description": "Setup link list",
8315
+ "content": {
8316
+ "application/json": {
8317
+ "schema": {
8318
+ "$ref": "#/components/schemas/ListCustomerSetupLinksResponse"
8319
+ }
8320
+ }
8321
+ }
8322
+ },
8323
+ "400": {
8324
+ "description": "Validation failure",
8325
+ "content": {
8326
+ "application/json": {
8327
+ "schema": {
8328
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
8329
+ }
8330
+ }
8331
+ }
8332
+ },
8333
+ "401": {
8334
+ "description": "Authentication failure",
8335
+ "content": {
8336
+ "application/json": {
8337
+ "schema": {
8338
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
8339
+ }
8340
+ }
8341
+ }
8342
+ },
8343
+ "404": {
8344
+ "description": "Resource not found",
8345
+ "content": {
8346
+ "application/json": {
8347
+ "schema": {
8348
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
8349
+ }
8350
+ }
8351
+ }
8352
+ },
8353
+ "429": {
8354
+ "description": "Rate limit exceeded",
8355
+ "content": {
8356
+ "application/json": {
8357
+ "schema": {
8358
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
8359
+ }
8360
+ }
8361
+ }
8362
+ },
8363
+ "500": {
8364
+ "description": "Internal server error",
8365
+ "content": {
8366
+ "application/json": {
8367
+ "schema": {
8368
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
8369
+ }
8370
+ }
8371
+ }
8372
+ }
8373
+ }
8374
+ },
8375
+ "post": {
8376
+ "tags": [
8377
+ "Customers"
8378
+ ],
8379
+ "summary": "Generate a setup link",
8380
+ "description": "Creates a one-time setup link the end-customer can use to complete Meta Embedded Signup. The plaintext token and full setup URL are returned EXACTLY ONCE — store them immediately.",
8381
+ "security": [
8382
+ {
8383
+ "bearerAuth": []
8384
+ }
8385
+ ],
8386
+ "parameters": [
8387
+ {
8388
+ "schema": {
8389
+ "type": "string",
8390
+ "pattern": "^cus_[0-9A-HJKMNP-TV-Z]{26}$"
8391
+ },
8392
+ "required": true,
8393
+ "name": "id",
8394
+ "in": "path"
8395
+ }
8396
+ ],
8397
+ "requestBody": {
8398
+ "content": {
8399
+ "application/json": {
8400
+ "schema": {
8401
+ "type": "object",
8402
+ "properties": {
8403
+ "expires_in_hours": {
8404
+ "type": "integer",
8405
+ "minimum": 1,
8406
+ "maximum": 720
8407
+ },
8408
+ "success_redirect_url": {
8409
+ "type": "string",
8410
+ "maxLength": 2048,
8411
+ "format": "uri"
8412
+ },
8413
+ "failure_redirect_url": {
8414
+ "type": "string",
8415
+ "maxLength": 2048,
8416
+ "format": "uri"
8417
+ }
8418
+ }
8419
+ }
8420
+ }
8421
+ }
8422
+ },
8423
+ "responses": {
8424
+ "200": {
8425
+ "description": "Setup link created (token returned ONCE)",
8426
+ "content": {
8427
+ "application/json": {
8428
+ "schema": {
8429
+ "$ref": "#/components/schemas/CreateCustomerSetupLinkResponse"
8430
+ }
8431
+ }
8432
+ }
8433
+ },
8434
+ "400": {
8435
+ "description": "Validation failure",
8436
+ "content": {
8437
+ "application/json": {
8438
+ "schema": {
8439
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
8440
+ }
8441
+ }
8442
+ }
8443
+ },
8444
+ "401": {
8445
+ "description": "Authentication failure",
8446
+ "content": {
8447
+ "application/json": {
8448
+ "schema": {
8449
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
8450
+ }
8451
+ }
8452
+ }
8453
+ },
8454
+ "404": {
8455
+ "description": "Resource not found",
8456
+ "content": {
8457
+ "application/json": {
8458
+ "schema": {
8459
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
8460
+ }
8461
+ }
8462
+ }
8463
+ },
8464
+ "429": {
8465
+ "description": "Rate limit exceeded",
8466
+ "content": {
8467
+ "application/json": {
8468
+ "schema": {
8469
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
8470
+ }
8471
+ }
8472
+ }
8473
+ },
8474
+ "500": {
8475
+ "description": "Internal server error",
8476
+ "content": {
8477
+ "application/json": {
8478
+ "schema": {
8479
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
8480
+ }
8481
+ }
8482
+ }
8483
+ }
8484
+ }
8485
+ }
8486
+ },
8487
+ "/customers/{id}/setup_links/{link_id}": {
8488
+ "patch": {
8489
+ "tags": [
8490
+ "Customers"
8491
+ ],
8492
+ "summary": "Update redirect URLs on an active setup link",
8493
+ "description": "Recover from a typo in `success_redirect_url` / `failure_redirect_url` without revoking and regenerating the link. Only works while `status = active`; pass `null` to clear a redirect.",
8494
+ "security": [
8495
+ {
8496
+ "bearerAuth": []
8497
+ }
8498
+ ],
8499
+ "parameters": [
8500
+ {
8501
+ "schema": {
8502
+ "type": "string",
8503
+ "pattern": "^cus_[0-9A-HJKMNP-TV-Z]{26}$"
8504
+ },
8505
+ "required": true,
8506
+ "name": "id",
8507
+ "in": "path"
8508
+ },
8509
+ {
8510
+ "schema": {
8511
+ "type": "string",
8512
+ "pattern": "^csl_[0-9A-HJKMNP-TV-Z]{26}$"
8513
+ },
8514
+ "required": true,
8515
+ "name": "link_id",
8516
+ "in": "path"
8517
+ }
8518
+ ],
8519
+ "requestBody": {
8520
+ "content": {
8521
+ "application/json": {
8522
+ "schema": {
8523
+ "type": "object",
8524
+ "properties": {
8525
+ "success_redirect_url": {
8526
+ "anyOf": [
8527
+ {
8528
+ "type": "string",
8529
+ "maxLength": 2048,
8530
+ "format": "uri"
8531
+ },
8532
+ {
8533
+ "type": "null"
8534
+ }
8535
+ ]
8536
+ },
8537
+ "failure_redirect_url": {
8538
+ "anyOf": [
8539
+ {
8540
+ "type": "string",
8541
+ "maxLength": 2048,
8542
+ "format": "uri"
8543
+ },
8544
+ {
8545
+ "type": "null"
8546
+ }
8547
+ ]
8548
+ }
8549
+ }
8550
+ }
8551
+ }
8552
+ }
8553
+ },
8554
+ "responses": {
8555
+ "200": {
8556
+ "description": "Updated setup link",
8557
+ "content": {
8558
+ "application/json": {
8559
+ "schema": {
8560
+ "$ref": "#/components/schemas/UpdateCustomerSetupLinkResponse"
8561
+ }
8562
+ }
8563
+ }
8564
+ },
8565
+ "400": {
8566
+ "description": "Validation failure",
8567
+ "content": {
8568
+ "application/json": {
8569
+ "schema": {
8570
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
8571
+ }
8572
+ }
8573
+ }
8574
+ },
8575
+ "401": {
8576
+ "description": "Authentication failure",
8577
+ "content": {
8578
+ "application/json": {
8579
+ "schema": {
8580
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
8581
+ }
8582
+ }
8583
+ }
8584
+ },
8585
+ "404": {
8586
+ "description": "Resource not found",
8587
+ "content": {
8588
+ "application/json": {
8589
+ "schema": {
8590
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
8591
+ }
8592
+ }
8593
+ }
8594
+ },
8595
+ "409": {
8596
+ "description": "Conflict (e.g. webhook subscription disabled)",
8597
+ "content": {
8598
+ "application/json": {
8599
+ "schema": {
8600
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
8601
+ }
8602
+ }
8603
+ }
8604
+ },
8605
+ "429": {
8606
+ "description": "Rate limit exceeded",
8607
+ "content": {
8608
+ "application/json": {
8609
+ "schema": {
8610
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
8611
+ }
8612
+ }
8613
+ }
8614
+ },
8615
+ "500": {
8616
+ "description": "Internal server error",
8617
+ "content": {
8618
+ "application/json": {
8619
+ "schema": {
8620
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
8621
+ }
8622
+ }
8623
+ }
8624
+ }
8625
+ }
8626
+ },
8627
+ "delete": {
8628
+ "tags": [
8629
+ "Customers"
8630
+ ],
8631
+ "summary": "Revoke a setup link",
8632
+ "description": "Revoke a still-active link. Already-consumed or already-revoked links return `409`.",
8633
+ "security": [
8634
+ {
8635
+ "bearerAuth": []
8636
+ }
8637
+ ],
8638
+ "parameters": [
8639
+ {
8640
+ "schema": {
8641
+ "type": "string",
8642
+ "pattern": "^cus_[0-9A-HJKMNP-TV-Z]{26}$"
8643
+ },
8644
+ "required": true,
8645
+ "name": "id",
8646
+ "in": "path"
8647
+ },
8648
+ {
8649
+ "schema": {
8650
+ "type": "string",
8651
+ "pattern": "^csl_[0-9A-HJKMNP-TV-Z]{26}$"
8652
+ },
8653
+ "required": true,
8654
+ "name": "link_id",
8655
+ "in": "path"
8656
+ }
8657
+ ],
8658
+ "responses": {
8659
+ "200": {
8660
+ "description": "Revoked",
8661
+ "content": {
8662
+ "application/json": {
8663
+ "schema": {
8664
+ "$ref": "#/components/schemas/RevokeCustomerSetupLinkResponse"
8665
+ }
8666
+ }
8667
+ }
8668
+ },
8669
+ "400": {
8670
+ "description": "Validation failure",
8671
+ "content": {
8672
+ "application/json": {
8673
+ "schema": {
8674
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
8675
+ }
8676
+ }
8677
+ }
8678
+ },
8679
+ "401": {
8680
+ "description": "Authentication failure",
8681
+ "content": {
8682
+ "application/json": {
8683
+ "schema": {
8684
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
8685
+ }
8686
+ }
8687
+ }
8688
+ },
8689
+ "404": {
8690
+ "description": "Resource not found",
8691
+ "content": {
8692
+ "application/json": {
8693
+ "schema": {
8694
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
8695
+ }
8696
+ }
8697
+ }
8698
+ },
8699
+ "409": {
8700
+ "description": "Conflict (e.g. webhook subscription disabled)",
8701
+ "content": {
8702
+ "application/json": {
8703
+ "schema": {
8704
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
8705
+ }
8706
+ }
8707
+ }
8708
+ },
8709
+ "429": {
8710
+ "description": "Rate limit exceeded",
8711
+ "content": {
8712
+ "application/json": {
8713
+ "schema": {
8714
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
8715
+ }
8716
+ }
8717
+ }
8718
+ },
8719
+ "500": {
8720
+ "description": "Internal server error",
8721
+ "content": {
8722
+ "application/json": {
8723
+ "schema": {
8724
+ "$ref": "#/components/schemas/ApiErrorEnvelope"
8725
+ }
8726
+ }
8727
+ }
8728
+ }
8729
+ }
8730
+ }
7139
8731
  }
7140
8732
  },
7141
8733
  "webhooks": {}