webflow-api 1.2.2 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -38,6 +38,41 @@ const webflow = new Webflow({
38
38
  });
39
39
  ```
40
40
 
41
+ ## Transitioning to API v2
42
+
43
+ We're actively working on a new version of the SDK that will fully support API v2. In the meantime, to make use of API v2 with our SDK, there are some important changes you need to be aware of:
44
+
45
+ ### Setting Up For API v2
46
+
47
+ When initializing your client, it's crucial to set the `beta` flag to true in the client options. This ensures you're targeting the API v2 endpoints.
48
+
49
+ ```javascript
50
+ const webflow = new Webflow({ beta: true, ...otherOptions });
51
+ ```
52
+
53
+ Please note, when the beta flag is set, several built-in methods will not be available. These methods include, but are not limited to, info, authenticatedUser, sites, site, etc. Attempting to use these will throw an error.
54
+
55
+ ### Calling API v2 Endpoints
56
+
57
+ To interact with API v2, you'll need to move away from using built-in methods, and instead use the provided HTTP methods directly.
58
+
59
+ For instance, where you previously used `sites()`:
60
+
61
+ ```javascript
62
+ // get the first site
63
+ const [site] = await webflow.sites();
64
+ ```
65
+
66
+ For API v2, you will need to use direct HTTP methods:
67
+
68
+ ```javascript
69
+ // get the first site
70
+ const sites = await webflow.get("/sites");
71
+ const site = sites[0];
72
+ ```
73
+
74
+ We understand that this is a shift in how you interact with the SDK, but rest assured, our upcoming SDK version will streamline this process and offer a more integrated experience with API v2.
75
+
41
76
  ## Basic Usage
42
77
 
43
78
  ### Chaining Calls
@@ -131,6 +166,20 @@ const url = webflow.authorizeUrl({
131
166
  res.redirect(url);
132
167
  ```
133
168
 
169
+ ### Using the scopes Parameter with v2 API
170
+
171
+ The v2 API introduces the concept of 'scopes', providing more control over app permissions. Instead of using the scope parameter as a single string, you can define multiple permissions using the scopes array:
172
+
173
+ ```javascript
174
+ const url = webflow.authorizeUrl({
175
+ client_id: "[CLIENT ID]",
176
+ redirect_uri: "https://my.server.com/oauth/callback",
177
+ scopes: ["read:sites", "write:items", "read:users"],
178
+ });
179
+ ```
180
+
181
+ For more information and a detailed list of available scopes, refer to our Scopes Guide.
182
+
134
183
  ### Access Token
135
184
 
136
185
  Once a user has authorized their Webflow resource(s), Webflow will redirect back to your server with a `code`. Use this to get an access token.
@@ -176,7 +225,7 @@ Get all sites available or lookup by site id.
176
225
  const sites = await webflow.sites();
177
226
 
178
227
  // Get a single site
179
- const site = await webflow.sites({ siteId: "[SITE ID]" });
228
+ const site = await webflow.site({ siteId: "[SITE ID]" });
180
229
  ```
181
230
 
182
231
  ### Collections
@@ -12,7 +12,7 @@ export declare type CollectionField = {
12
12
  name: string;
13
13
  required: boolean;
14
14
  editable: boolean;
15
- validations?: Record<string, string | number | boolean | object>;
15
+ validations?: Record<string, any>;
16
16
  };
17
17
  /**************************************************************
18
18
  * Interfaces
@@ -31,7 +31,7 @@ export interface IDeletedItems {
31
31
  /**************************************************************
32
32
  * Types
33
33
  **************************************************************/
34
- export declare type PageinatedItems = PaginatedData & {
34
+ export declare type PaginatedItems = PaginatedData & {
35
35
  items: IItem[];
36
36
  };
37
37
  /**************************************************************
@@ -64,7 +64,7 @@ export declare class Item extends WebflowRecord<IItem> implements IItem {
64
64
  static getOne({ collectionId, itemId }: {
65
65
  collectionId: string;
66
66
  itemId: string;
67
- }, client: AxiosInstance): Promise<import("axios").AxiosResponse<PageinatedItems, any>>;
67
+ }, client: AxiosInstance): Promise<import("axios").AxiosResponse<PaginatedItems, any>>;
68
68
  /**
69
69
  * Get a list of Items
70
70
  * @param params The params for the request
@@ -78,7 +78,7 @@ export declare class Item extends WebflowRecord<IItem> implements IItem {
78
78
  collectionId: string;
79
79
  limit?: number;
80
80
  offset?: number;
81
- }, client: AxiosInstance): Promise<import("axios").AxiosResponse<PageinatedItems, any>>;
81
+ }, client: AxiosInstance): Promise<import("axios").AxiosResponse<PaginatedItems, any>>;
82
82
  /**
83
83
  * Create a new Item
84
84
  * @param params The params for the request
@@ -132,7 +132,7 @@ export declare class Item extends WebflowRecord<IItem> implements IItem {
132
132
  collectionId: string;
133
133
  }, client: AxiosInstance): Promise<import("axios").AxiosResponse<IItemDelete, any>>;
134
134
  /**
135
- * Unpublishes a list of Items
135
+ * Unpublish a list of Items
136
136
  * @param params The params for the request
137
137
  * @param params.collectionId The Collection ID
138
138
  * @param params.live Unpublish from the live site
package/dist/api/item.js CHANGED
@@ -93,7 +93,7 @@ class Item extends core_1.WebflowRecord {
93
93
  return client.delete(path);
94
94
  }
95
95
  /**
96
- * Unpublishes a list of Items
96
+ * Unpublish a list of Items
97
97
  * @param params The params for the request
98
98
  * @param params.collectionId The Collection ID
99
99
  * @param params.live Unpublish from the live site
@@ -21,7 +21,7 @@ export interface IAuthenticatedUser {
21
21
  _id: string;
22
22
  };
23
23
  }
24
- export interface IAuthentiationInfo {
24
+ export interface IAuthenticationInfo {
25
25
  application: InfoApplication;
26
26
  workspaces: string[];
27
27
  rateLimit: number;
@@ -43,7 +43,7 @@ export declare class Meta {
43
43
  * @param client The Axios client instance
44
44
  * @returns The authentication info
45
45
  */
46
- static info(client: AxiosInstance): Promise<import("axios").AxiosResponse<IAuthentiationInfo, any>>;
46
+ static info(client: AxiosInstance): Promise<import("axios").AxiosResponse<IAuthenticationInfo, any>>;
47
47
  /**
48
48
  * Get the authenticated user
49
49
  * @param client The Axios client instance
@@ -1,10 +1,12 @@
1
1
  import { AxiosInstance } from "axios";
2
+ import { SupportedScope } from "../core";
2
3
  /**************************************************************
3
4
  * Interfaces
4
5
  **************************************************************/
5
6
  export interface IAuthorizeUrlParams {
6
7
  state?: string;
7
8
  scope?: string;
9
+ scopes?: SupportedScope[];
8
10
  client_id: string;
9
11
  redirect_uri?: string;
10
12
  response_type?: string;
@@ -43,7 +45,7 @@ export declare class OAuth {
43
45
  * @param client The Axios client instance
44
46
  * @returns The URL to authorize a user
45
47
  */
46
- static authorizeUrl({ response_type, redirect_uri, client_id, state, scope }: IAuthorizeUrlParams, client: AxiosInstance): string;
48
+ static authorizeUrl({ response_type, redirect_uri, client_id, state, scope, scopes }: IAuthorizeUrlParams, client: AxiosInstance): string;
47
49
  /**
48
50
  * Get an access token
49
51
  * @param params The params for the request
package/dist/api/oauth.js CHANGED
@@ -17,8 +17,11 @@ class OAuth {
17
17
  * @param client The Axios client instance
18
18
  * @returns The URL to authorize a user
19
19
  */
20
- static authorizeUrl({ response_type = "code", redirect_uri, client_id, state, scope }, client) {
20
+ static authorizeUrl({ response_type = "code", redirect_uri, client_id, state, scope, scopes }, client) {
21
21
  (0, core_1.requireArgs)({ client_id });
22
+ if (scope && scopes) {
23
+ throw new Error("Please provide either 'scope' or 'scopes', but not both.");
24
+ }
22
25
  const params = { response_type, client_id };
23
26
  if (redirect_uri)
24
27
  params["redirect_uri"] = redirect_uri;
@@ -26,6 +29,8 @@ class OAuth {
26
29
  params["state"] = state;
27
30
  if (scope)
28
31
  params["scope"] = scope;
32
+ if (scopes && scopes.length > 0)
33
+ params["scope"] = scopes.join("+");
29
34
  const url = "/oauth/authorize";
30
35
  const baseURL = client.defaults.baseURL.replace("api.", "");
31
36
  return client.getUri({ baseURL, url, method: "GET", params });
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ErrorInterceptor = exports.requireArgs = exports.ArgumentError = exports.RequestError = void 0;
4
4
  class RequestError extends Error {
5
5
  constructor(error) {
6
- super(error.err ? error.err : "Unknown error occured");
6
+ super(error.err ? error.err : "Unknown error occurred");
7
7
  Object.assign(this, error);
8
8
  }
9
9
  }
@@ -8,7 +8,10 @@ export interface Options {
8
8
  token?: string;
9
9
  version?: string;
10
10
  headers?: Record<string, string>;
11
+ beta?: boolean;
11
12
  }
13
+ export declare const SCOPES_ARRAY: readonly ["assets:read", "assets:write", "authorized_user:read", "cms:read", "cms:write", "custom_code:read", "custom_code:write", "forms:read", "forms:write", "pages:read", "pages:write", "sites:read", "sites:write", "users:read", "users:write", "ecommerce:read", "ecommerce:write"];
14
+ export declare type SupportedScope = typeof SCOPES_ARRAY[number];
12
15
  /**************************************************************
13
16
  * Class
14
17
  **************************************************************/
@@ -16,6 +19,7 @@ export declare class Webflow {
16
19
  options: Options;
17
20
  private client;
18
21
  constructor(options?: Options);
22
+ private removeNonBetaMethods;
19
23
  set token(value: string);
20
24
  clearToken(): void;
21
25
  get config(): AxiosRequestConfig<any>;
@@ -101,7 +105,7 @@ export declare class Webflow {
101
105
  * Get the current authorization information
102
106
  * @returns The authorization information
103
107
  */
104
- info(): Promise<import("../api").IAuthentiationInfo>;
108
+ info(): Promise<import("../api").IAuthenticationInfo>;
105
109
  /**
106
110
  * Get the current authenticated user
107
111
  * @returns The current authenticated user
@@ -236,7 +240,7 @@ export declare class Webflow {
236
240
  collectionId: string;
237
241
  }): Promise<import("../api").IItemDelete>;
238
242
  /**
239
- * Upublish a Collection Item
243
+ * Unpublish a Collection Item
240
244
  * @param params The Item information
241
245
  * @param params.collectionId The Collection ID
242
246
  * @param params.itemId The Item ID
@@ -374,7 +378,7 @@ export declare class Webflow {
374
378
  * @param params.siteId The Site Id
375
379
  * @param params.url The Url the Webhook should call on events
376
380
  * @param params.triggerType The type of event that should trigger the Webhook
377
- * @param params.filter The filter to apply to the Webhook (form_submssion only)
381
+ * @param params.filter The filter to apply to the Webhook (form_submission only)
378
382
  * @returns The created webhook
379
383
  */
380
384
  createWebhook({ url, siteId, triggerType, filter, }: {
@@ -3,12 +3,31 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.Webflow = exports.USER_AGENT = exports.DEFAULT_HOST = void 0;
6
+ exports.Webflow = exports.SCOPES_ARRAY = exports.USER_AGENT = exports.DEFAULT_HOST = void 0;
7
7
  const axios_1 = __importDefault(require("axios"));
8
8
  const core_1 = require("../core");
9
9
  const api_1 = require("../api");
10
10
  exports.DEFAULT_HOST = "webflow.com";
11
11
  exports.USER_AGENT = "Webflow Javascript SDK / 1.0";
12
+ exports.SCOPES_ARRAY = [
13
+ "assets:read",
14
+ "assets:write",
15
+ "authorized_user:read",
16
+ "cms:read",
17
+ "cms:write",
18
+ "custom_code:read",
19
+ "custom_code:write",
20
+ "forms:read",
21
+ "forms:write",
22
+ "pages:read",
23
+ "pages:write",
24
+ "sites:read",
25
+ "sites:write",
26
+ "users:read",
27
+ "users:write",
28
+ "ecommerce:read",
29
+ "ecommerce:write",
30
+ ];
12
31
  /**************************************************************
13
32
  * Class
14
33
  **************************************************************/
@@ -17,6 +36,38 @@ class Webflow {
17
36
  this.options = options;
18
37
  this.client = axios_1.default.create(this.config);
19
38
  this.client.interceptors.response.use(core_1.ErrorInterceptor);
39
+ if (this.options.beta) {
40
+ this.removeNonBetaMethods();
41
+ }
42
+ }
43
+ removeNonBetaMethods() {
44
+ const methodsToRemove = [
45
+ "info",
46
+ "authenticatedUser",
47
+ "sites",
48
+ "site",
49
+ "publishSite",
50
+ "domains",
51
+ "collections",
52
+ "collection",
53
+ "items",
54
+ "item",
55
+ "createItem",
56
+ "updateItem",
57
+ "patchItem",
58
+ "removeItem",
59
+ "deleteItems",
60
+ "publishItems",
61
+ ];
62
+ methodsToRemove.forEach((method) => {
63
+ Object.defineProperty(this, method, {
64
+ value: function () {
65
+ throw new Error(`The method '${method}()' is not available in beta mode. Please disable the beta option to use this method.`);
66
+ },
67
+ enumerable: false,
68
+ configurable: true,
69
+ });
70
+ });
20
71
  }
21
72
  // Set the Authentication token
22
73
  set token(value) {
@@ -28,9 +79,10 @@ class Webflow {
28
79
  }
29
80
  // The Axios configuration
30
81
  get config() {
31
- const { host = exports.DEFAULT_HOST, token, version, headers } = this.options;
82
+ const { host = exports.DEFAULT_HOST, token, version, headers, beta = false } = this.options;
83
+ const effectiveHost = beta ? "webflow.com/beta" : host;
32
84
  const config = {
33
- baseURL: `https://api.${host}/`,
85
+ baseURL: `https://api.${effectiveHost}/`,
34
86
  headers: {
35
87
  "Content-Type": "application/json",
36
88
  "User-Agent": exports.USER_AGENT,
@@ -43,6 +95,27 @@ class Webflow {
43
95
  // Add the Authorization header if a token is set
44
96
  if (token)
45
97
  config.headers.Authorization = `Bearer ${token}`;
98
+ config.paramsSerializer = {
99
+ serialize: (params) => {
100
+ if (typeof params !== "object" || params === null) {
101
+ return "";
102
+ }
103
+ const parts = [];
104
+ for (const key in params) {
105
+ const value = params[key];
106
+ if (value === undefined)
107
+ continue;
108
+ const safeValue = typeof value === "string" || typeof value === "number" ? value : String(value);
109
+ if (key === "scope") {
110
+ parts.push(`${key}=${safeValue}`);
111
+ }
112
+ else {
113
+ parts.push(`${key}=${encodeURIComponent(safeValue)}`);
114
+ }
115
+ }
116
+ return parts.join("&");
117
+ },
118
+ };
46
119
  return config;
47
120
  }
48
121
  /**************************************************************
@@ -296,7 +369,7 @@ class Webflow {
296
369
  return res.data;
297
370
  }
298
371
  /**
299
- * Upublish a Collection Item
372
+ * Unpublish a Collection Item
300
373
  * @param params The Item information
301
374
  * @param params.collectionId The Collection ID
302
375
  * @param params.itemId The Item ID
@@ -433,7 +506,7 @@ class Webflow {
433
506
  * @param params.siteId The Site Id
434
507
  * @param params.url The Url the Webhook should call on events
435
508
  * @param params.triggerType The type of event that should trigger the Webhook
436
- * @param params.filter The filter to apply to the Webhook (form_submssion only)
509
+ * @param params.filter The filter to apply to the Webhook (form_submission only)
437
510
  * @returns The created webhook
438
511
  */
439
512
  async createWebhook({ url, siteId, triggerType, filter, }) {
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "webflow-api",
3
3
  "description": "Webflow's official Node.js SDK for Data APIs",
4
- "version": "1.2.2",
4
+ "version": "1.3.1",
5
5
  "types": "dist/index.d.ts",
6
6
  "main": "dist/index.js",
7
7
  "contributors": [
8
+ "Rodney Urquhart (https://github.com/rodneyu215)",
8
9
  "John Agan (https://github.com/johnagan)"
9
10
  ],
10
11
  "repository": {
@@ -32,7 +32,7 @@ export type CollectionField = {
32
32
  required: boolean;
33
33
  editable: boolean;
34
34
  // TODO: add a better type
35
- validations?: Record<string, string | number | boolean | object>;
35
+ validations?: Record<string, any>;
36
36
  };
37
37
 
38
38
  /**************************************************************
package/src/api/item.ts CHANGED
@@ -36,7 +36,7 @@ export interface IDeletedItems {
36
36
  /**************************************************************
37
37
  * Types
38
38
  **************************************************************/
39
- export type PageinatedItems = PaginatedData & {
39
+ export type PaginatedItems = PaginatedData & {
40
40
  items: IItem[];
41
41
  };
42
42
 
@@ -77,7 +77,7 @@ export class Item extends WebflowRecord<IItem> implements IItem {
77
77
  requireArgs({ collectionId, itemId });
78
78
  const path = `/collections/${collectionId}/items/${itemId}`;
79
79
  // The API returns a paginated list with one record :(
80
- return client.get<PageinatedItems>(path);
80
+ return client.get<PaginatedItems>(path);
81
81
  }
82
82
 
83
83
  /**
@@ -96,7 +96,7 @@ export class Item extends WebflowRecord<IItem> implements IItem {
96
96
  requireArgs({ collectionId });
97
97
  const params = { limit, offset };
98
98
  const path = `/collections/${collectionId}/items`;
99
- return client.get<PageinatedItems>(path, { params });
99
+ return client.get<PaginatedItems>(path, { params });
100
100
  }
101
101
 
102
102
  /**
@@ -192,7 +192,7 @@ export class Item extends WebflowRecord<IItem> implements IItem {
192
192
  }
193
193
 
194
194
  /**
195
- * Unpublishes a list of Items
195
+ * Unpublish a list of Items
196
196
  * @param params The params for the request
197
197
  * @param params.collectionId The Collection ID
198
198
  * @param params.live Unpublish from the live site
package/src/api/meta.ts CHANGED
@@ -24,7 +24,7 @@ export interface IAuthenticatedUser {
24
24
  };
25
25
  }
26
26
 
27
- export interface IAuthentiationInfo {
27
+ export interface IAuthenticationInfo {
28
28
  application: InfoApplication;
29
29
  workspaces: string[];
30
30
  rateLimit: number;
@@ -48,7 +48,7 @@ export class Meta {
48
48
  * @returns The authentication info
49
49
  */
50
50
  static info(client: AxiosInstance) {
51
- return client.get<IAuthentiationInfo>("/info");
51
+ return client.get<IAuthenticationInfo>("/info");
52
52
  }
53
53
 
54
54
  /**
package/src/api/oauth.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { AxiosInstance } from "axios";
2
- import { requireArgs } from "../core";
2
+ import { requireArgs, SupportedScope } from "../core";
3
3
 
4
4
  /**************************************************************
5
5
  * Interfaces
@@ -7,6 +7,7 @@ import { requireArgs } from "../core";
7
7
  export interface IAuthorizeUrlParams {
8
8
  state?: string;
9
9
  scope?: string;
10
+ scopes?: SupportedScope[];
10
11
  client_id: string;
11
12
  redirect_uri?: string;
12
13
  response_type?: string;
@@ -52,15 +53,20 @@ export class OAuth {
52
53
  * @returns The URL to authorize a user
53
54
  */
54
55
  static authorizeUrl(
55
- { response_type = "code", redirect_uri, client_id, state, scope }: IAuthorizeUrlParams,
56
+ { response_type = "code", redirect_uri, client_id, state, scope, scopes }: IAuthorizeUrlParams,
56
57
  client: AxiosInstance,
57
58
  ) {
58
59
  requireArgs({ client_id });
59
60
 
61
+ if (scope && scopes) {
62
+ throw new Error("Please provide either 'scope' or 'scopes', but not both.");
63
+ }
64
+
60
65
  const params = { response_type, client_id };
61
66
  if (redirect_uri) params["redirect_uri"] = redirect_uri;
62
67
  if (state) params["state"] = state;
63
68
  if (scope) params["scope"] = scope;
69
+ if (scopes && scopes.length > 0) params["scope"] = scopes.join("+");
64
70
 
65
71
  const url = "/oauth/authorize";
66
72
  const baseURL = client.defaults.baseURL.replace("api.", "");
package/src/core/error.ts CHANGED
@@ -16,7 +16,7 @@ export class RequestError extends Error implements IRequestError {
16
16
  err: string;
17
17
 
18
18
  constructor(error: IRequestError) {
19
- super(error.err ? error.err : "Unknown error occured");
19
+ super(error.err ? error.err : "Unknown error occurred");
20
20
  Object.assign(this, error);
21
21
  }
22
22
  }
@@ -22,8 +22,51 @@ export interface Options {
22
22
  token?: string;
23
23
  version?: string;
24
24
  headers?: Record<string, string>;
25
+ beta?: boolean;
25
26
  }
26
27
 
28
+ type MethodNames =
29
+ | "info"
30
+ | "authenticatedUser"
31
+ | "sites"
32
+ | "site"
33
+ | "publishSite"
34
+ | "domains"
35
+ | "collections"
36
+ | "collection"
37
+ | "items"
38
+ | "item"
39
+ | "createItem"
40
+ | "updateItem"
41
+ | "patchItem"
42
+ | "removeItem"
43
+ | "deleteItems"
44
+ | "publishItems";
45
+
46
+ export const SCOPES_ARRAY = [
47
+ "assets:read",
48
+ "assets:write",
49
+ "authorized_user:read",
50
+ "cms:read",
51
+ "cms:write",
52
+ "custom_code:read",
53
+ "custom_code:write",
54
+ "forms:read",
55
+ "forms:write",
56
+ "pages:read",
57
+ "pages:write",
58
+ "sites:read",
59
+ "sites:write",
60
+ "users:read",
61
+ "users:write",
62
+ "ecommerce:read",
63
+ "ecommerce:write",
64
+ ] as const;
65
+
66
+ export type SupportedScope = typeof SCOPES_ARRAY[number];
67
+
68
+ type ParamValueType = string | number | boolean | null | undefined;
69
+
27
70
  /**************************************************************
28
71
  * Class
29
72
  **************************************************************/
@@ -32,6 +75,43 @@ export class Webflow {
32
75
  constructor(public options: Options = {}) {
33
76
  this.client = axios.create(this.config);
34
77
  this.client.interceptors.response.use(ErrorInterceptor);
78
+
79
+ if (this.options.beta) {
80
+ this.removeNonBetaMethods();
81
+ }
82
+ }
83
+
84
+ private removeNonBetaMethods() {
85
+ const methodsToRemove: MethodNames[] = [
86
+ "info",
87
+ "authenticatedUser",
88
+ "sites",
89
+ "site",
90
+ "publishSite",
91
+ "domains",
92
+ "collections",
93
+ "collection",
94
+ "items",
95
+ "item",
96
+ "createItem",
97
+ "updateItem",
98
+ "patchItem",
99
+ "removeItem",
100
+ "deleteItems",
101
+ "publishItems",
102
+ ];
103
+
104
+ methodsToRemove.forEach((method) => {
105
+ Object.defineProperty(this, method, {
106
+ value: function (): never {
107
+ throw new Error(
108
+ `The method '${method}()' is not available in beta mode. Please disable the beta option to use this method.`,
109
+ );
110
+ },
111
+ enumerable: false,
112
+ configurable: true,
113
+ });
114
+ });
35
115
  }
36
116
 
37
117
  // Set the Authentication token
@@ -46,10 +126,11 @@ export class Webflow {
46
126
 
47
127
  // The Axios configuration
48
128
  get config() {
49
- const { host = DEFAULT_HOST, token, version, headers } = this.options;
129
+ const { host = DEFAULT_HOST, token, version, headers, beta = false } = this.options;
130
+ const effectiveHost = beta ? "webflow.com/beta" : host;
50
131
 
51
132
  const config: AxiosRequestConfig = {
52
- baseURL: `https://api.${host}/`,
133
+ baseURL: `https://api.${effectiveHost}/`,
53
134
  headers: {
54
135
  "Content-Type": "application/json",
55
136
  "User-Agent": USER_AGENT,
@@ -63,6 +144,32 @@ export class Webflow {
63
144
  // Add the Authorization header if a token is set
64
145
  if (token) config.headers.Authorization = `Bearer ${token}`;
65
146
 
147
+ config.paramsSerializer = {
148
+ serialize: (params: Record<string, ParamValueType>): string => {
149
+ if (typeof params !== "object" || params === null) {
150
+ return "";
151
+ }
152
+
153
+ const parts: string[] = [];
154
+
155
+ for (const key in params) {
156
+ const value = params[key];
157
+ if (value === undefined) continue;
158
+
159
+ const safeValue =
160
+ typeof value === "string" || typeof value === "number" ? value : String(value);
161
+
162
+ if (key === "scope") {
163
+ parts.push(`${key}=${safeValue}`);
164
+ } else {
165
+ parts.push(`${key}=${encodeURIComponent(safeValue)}`);
166
+ }
167
+ }
168
+
169
+ return parts.join("&");
170
+ },
171
+ };
172
+
66
173
  return config;
67
174
  }
68
175
 
@@ -328,7 +435,7 @@ export class Webflow {
328
435
  return res.data;
329
436
  }
330
437
  /**
331
- * Upublish a Collection Item
438
+ * Unpublish a Collection Item
332
439
  * @param params The Item information
333
440
  * @param params.collectionId The Collection ID
334
441
  * @param params.itemId The Item ID
@@ -503,7 +610,7 @@ export class Webflow {
503
610
  * @param params.siteId The Site Id
504
611
  * @param params.url The Url the Webhook should call on events
505
612
  * @param params.triggerType The type of event that should trigger the Webhook
506
- * @param params.filter The filter to apply to the Webhook (form_submssion only)
613
+ * @param params.filter The filter to apply to the Webhook (form_submission only)
507
614
  * @returns The created webhook
508
615
  */
509
616
  async createWebhook({