@hostinger/mcp 3.3.1 → 3.4.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/CHANGELOG.md CHANGED
@@ -4,6 +4,38 @@ Generated at release time from the diff between the previous and current
4
4
  build. Tool changes are listed individually; everything else is summarised
5
5
  by area.
6
6
 
7
+ ## v3.4.1 — 2026-10-21
8
+
9
+ ### Operations
10
+
11
+ - Added `reach_forms_update` — Update form
12
+ - Added `reach_forms_duplicate` — Duplicate form
13
+ - Added `reach_forms_create` — Create form
14
+ - Added `reach_forms_add-submitter-tags` — Add form submitter tags
15
+ - Added `reach_forms_remove-submitter-tag` — Remove form submitter tag
16
+ - Added `reach_forms_update-template` — Update form template
17
+ - Changed the input schema of `reach_forms_list`
18
+
19
+ ### Also in this release
20
+
21
+ - Documentation: `README.md`
22
+ - Dependencies: `package-lock.json`
23
+ - Request handling and authentication: `src/core/runtime.js`, `src/core/runtime.ts`
24
+ - Build and packaging: `types.d.ts`
25
+
26
+ ## v3.4.0 — 2026-10-20
27
+
28
+ ### Operations
29
+
30
+ - Changed the description and input schema of `hosting_deploy`
31
+
32
+ ### Also in this release
33
+
34
+ - Documentation: `README.md`
35
+ - Dependencies: `package-lock.json`
36
+ - Request handling and authentication: `src/core/runtime.js`, `src/core/runtime.ts`
37
+ - Build and packaging: `types.d.ts`
38
+
7
39
  ## v3.3.1 — 2026-10-19
8
40
 
9
41
  ### Also in this release
package/README.md CHANGED
@@ -69,7 +69,7 @@ pnpm update -g @hostinger/mcp
69
69
 
70
70
  This package installs the following MCP server commands:
71
71
 
72
- - `hostinger-api-mcp` — unified server over every operation (403 total)
72
+ - `hostinger-api-mcp` — unified server over every operation (409 total)
73
73
  - `hostinger-agency-hosting-mcp` — 42 operations for agency-hosting
74
74
  - `hostinger-agent-readiness-mcp` — 3 operations for agent-readiness
75
75
  - `hostinger-billing-mcp` — 9 operations for billing
@@ -79,7 +79,7 @@ This package installs the following MCP server commands:
79
79
  - `hostinger-horizons-mcp` — 6 operations for horizons
80
80
  - `hostinger-hosting-mcp` — 66 operations for hosting
81
81
  - `hostinger-mail-mcp` — 38 operations for mail
82
- - `hostinger-reach-mcp` — 56 operations for reach
82
+ - `hostinger-reach-mcp` — 62 operations for reach
83
83
  - `hostinger-vps-mcp` — 67 operations for vps
84
84
  - `hostinger-wordpress-mcp` — 40 operations for wordpress
85
85
 
@@ -1816,7 +1816,7 @@ interface in the provided website URL.
1816
1816
 
1817
1817
  #### hosting_deploy
1818
1818
 
1819
- Deploy, publish or upload a website to Hostinger web hosting (Shared, Cloud): static HTML, PHP, a nodejs (Node.js) app, a whole WordPress site, or a WordPress plugin or theme, from a local directory, an archive or a GitHub or GitLab repository. It detects what the project is and does the upload, build and Git setup itself: do not call upload or build operations, and do not archive the directory yourself. WARNING: it overwrites the website's contents and cannot be undone; confirm the domain with the user before deploying to a site that already has content. A Node.js build runs on the server: this returns a buildUuid at once, then call hosting_get-deployment until the build state is completed or failed. Static, PHP, plugin and theme deploys are done when this returns; a WordPress site import only starts, and its files are extracted a few minutes later. From Git, pass type (static or nodejs) unless the site already runs a Node.js app or you pass Node.js settings; a static or PHP site deploys the branch now and again on every push; a Node.js site builds the branch now and on every later push, with the settings stored for the site (when none are stored, pass appType and nodeVersion from the project's engines, plus outputDirectory and buildScript if the app has a build step). Git needs GitHub or GitLab connected once in hPanel.
1819
+ Deploy, publish or upload a website to Hostinger web hosting (Shared, Cloud): static HTML, PHP, a nodejs (Node.js) app, a whole WordPress site, or a WordPress plugin or theme, from a local directory, an archive or a GitHub or GitLab repository. It detects what the project is and does the upload, build and Git setup itself: do not call upload or build operations, and do not archive the directory yourself. WARNING: it overwrites the website's contents and cannot be undone; confirm the domain with the user before deploying to a site that already has content. A Node.js build runs on the server: this returns a buildUuid at once, then call hosting_get-deployment until the build state is completed or failed. For a plugin or theme on a headless WordPress (installed in the cms folder), pass headless: true. Static, PHP, plugin and theme deploys are done when this returns; a WordPress site import only starts, and its files are extracted a few minutes later. From Git, pass type (static or nodejs) unless the site already runs a Node.js app or you pass Node.js settings; a static or PHP site deploys the branch now and again on every push; a Node.js site builds the branch now and on every later push, with the settings stored for the site (when none are stored, pass appType and nodeVersion from the project's engines, plus outputDirectory and buildScript if the app has a build step). Git needs GitHub or GitLab connected once in hPanel.
1820
1820
 
1821
1821
  - **Method**: `custom`
1822
1822
  - **Path**: `custom`
@@ -3490,6 +3490,29 @@ do not block deletion.
3490
3490
  - **Method**: `DELETE`
3491
3491
  - **Path**: `/api/reach/v1/profiles/{profileUuid}/forms/{formUuid}`
3492
3492
 
3493
+ #### reach_forms_update
3494
+
3495
+ Rename a form and/or change its status.
3496
+
3497
+ Setting a `draft` or `paused` form to `active` takes it live: its latest saved design is published
3498
+ and visitors can submit it. `paused` and `draft` stop the form from accepting submissions. A form is
3499
+ not reachable by visitors until it is taken live. Design changes saved while the form is already
3500
+ `active` stay unpublished until the form is paused and set to `active` again. Renaming does not rename
3501
+ the automatic `form:{name}` tag.
3502
+
3503
+ - **Method**: `PATCH`
3504
+ - **Path**: `/api/reach/v1/profiles/{profileUuid}/forms/{formUuid}`
3505
+
3506
+ #### reach_forms_duplicate
3507
+
3508
+ Copy a form into a new draft form with the same name and design.
3509
+
3510
+ The copy shares the source's automatic `form:{name}` tag; other submitter tags are not copied. The
3511
+ copy is not live until its status is set to `active`.
3512
+
3513
+ - **Method**: `POST`
3514
+ - **Path**: `/api/reach/v1/profiles/{profileUuid}/forms/{formUuid}/duplicate`
3515
+
3493
3516
  #### reach_forms_list
3494
3517
 
3495
3518
  Get a paginated list of the signup forms in a profile.
@@ -3500,6 +3523,56 @@ directly usable template URL and for the tags the form puts on the contacts it c
3500
3523
  - **Method**: `GET`
3501
3524
  - **Path**: `/api/reach/v1/profiles/{profileUuid}/forms`
3502
3525
 
3526
+ #### reach_forms_create
3527
+
3528
+ Create an empty draft form.
3529
+
3530
+ Reach also adds an automatic `form:{name}` tag that every submitter receives. A draft has no design
3531
+ and is not reachable by visitors: save a design with the update form template operation, then take
3532
+ the form live by setting its status to `active`. Creating a form does not consume AI credits.
3533
+
3534
+ - **Method**: `POST`
3535
+ - **Path**: `/api/reach/v1/profiles/{profileUuid}/forms`
3536
+
3537
+ #### reach_forms_add-submitter-tags
3538
+
3539
+ Add tags to a form so that every contact who submits it from now on receives them.
3540
+
3541
+ A tag the form already has is skipped; an unknown tag is rejected. Contacts who submitted earlier are
3542
+ not tagged.
3543
+
3544
+ - **Method**: `POST`
3545
+ - **Path**: `/api/reach/v1/profiles/{profileUuid}/forms/{formUuid}/tags`
3546
+
3547
+ #### reach_forms_remove-submitter-tag
3548
+
3549
+ Stop a form from applying a tag to its future submitters.
3550
+
3551
+ Succeeds also when the form did not have the tag. Contacts who already received the tag keep it, and
3552
+ the tag itself is not deleted. The automatic `form:{name}` tag cannot be removed and is rejected with
3553
+ a conflict.
3554
+
3555
+ - **Method**: `DELETE`
3556
+ - **Path**: `/api/reach/v1/profiles/{profileUuid}/forms/{formUuid}/tags`
3557
+
3558
+ #### reach_forms_update-template
3559
+
3560
+ Save `content` as the latest design of a form and return the stored version.
3561
+
3562
+ The HTML is sanitized and, unless the plan allows removing it, the Reach signature is added. Visitors
3563
+ submit the form with an `email` field (required) and optional `name`, `surname` and `phone`. After
3564
+ sanitizing, the design must contain a form container (`data-reach-form`), an email input
3565
+ (`data-reach-field="email"`) and a submit button (`data-reach-submit`); otherwise the request fails
3566
+ with `422` and `errors.content` lists `missing_form_container`, `missing_email_field` and/or
3567
+ `missing_submit_button`.
3568
+
3569
+ A `draft` or `paused` form stays unreachable until its status is set to `active`, which publishes this
3570
+ design. On a form that is already `active` the saved design is not public until the form is paused and
3571
+ set to `active` again. Saving a design does not consume AI credits.
3572
+
3573
+ - **Method**: `PATCH`
3574
+ - **Path**: `/api/reach/v1/profiles/{profileUuid}/forms/{formUuid}/template`
3575
+
3503
3576
  #### reach_profiles_connected-sending-domain
3504
3577
 
3505
3578
  Get the sending domain connected to the profile, its verification status and any suspended
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hostinger-api-mcp",
3
- "version": "3.3.1",
3
+ "version": "3.4.1",
4
4
  "description": "Hostinger API — manage domains, DNS, hosting, VPS, billing and more from Gemini CLI.",
5
5
  "mcpServers": {
6
6
  "hostinger": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hostinger/mcp",
3
- "version": "3.3.1",
3
+ "version": "3.4.1",
4
4
  "mcpName": "io.github.hostinger/hostinger-api-mcp",
5
5
  "description": "MCP server for Hostinger API",
6
6
  "repository": {
package/server.json CHANGED
@@ -6,12 +6,12 @@
6
6
  "url": "https://github.com/hostinger/api-mcp-server",
7
7
  "source": "github"
8
8
  },
9
- "version": "3.3.1",
9
+ "version": "3.4.1",
10
10
  "packages": [
11
11
  {
12
12
  "registryType": "npm",
13
13
  "identifier": "@hostinger/mcp",
14
- "version": "3.3.1",
14
+ "version": "3.4.1",
15
15
  "transport": {
16
16
  "type": "stdio"
17
17
  },
@@ -66,7 +66,7 @@ const GetSkillRequestSchema = z.object({
66
66
 
67
67
  /**
68
68
  * MCP Server for Hostinger API
69
- * Generated from OpenAPI spec version 2.1.2
69
+ * Generated from OpenAPI spec version 2.1.3
70
70
  */
71
71
  class MCPServer {
72
72
  constructor({ name, version, tools, instructions, skills = [] }) {
@@ -643,6 +643,9 @@ class MCPServer {
643
643
  if (resolved === 'wordpress-site' && !databaseDump) {
644
644
  throw new Error('databaseDump (path to a .sql file) is required to import a WordPress site');
645
645
  }
646
+ if (params.headless === true && resolved !== 'wordpress-plugin' && resolved !== 'wordpress-theme') {
647
+ throw new Error('headless is for wordpress-plugin and wordpress-theme deploys only, not ' + resolved);
648
+ }
646
649
  return resolved;
647
650
  }
648
651
 
@@ -823,6 +826,12 @@ class MCPServer {
823
826
  if (params.slug !== undefined && !(typeof params.slug === 'string' && /^[a-z0-9_-]+$/.test(params.slug))) {
824
827
  throw new Error('slug must contain only lower-case letters, digits, "-" and "_"');
825
828
  }
829
+ if (params.headless !== undefined && typeof params.headless !== 'boolean') {
830
+ throw new Error('headless must be a boolean');
831
+ }
832
+ if (params.headless === true && git !== undefined) {
833
+ throw new Error('headless is for wordpress-plugin and wordpress-theme deploys only, which need a local directory, not git');
834
+ }
826
835
  if (git !== undefined && (typeof git !== 'object' || git === null || typeof git.repository !== 'string' || typeof git.branch !== 'string' || git.branch === '')) {
827
836
  throw new Error('git must be an object with repository (owner/name) and branch');
828
837
  }
@@ -846,6 +855,9 @@ class MCPServer {
846
855
  theme: '/api/hosting/v1/accounts/{username}/websites/{domain}/wordpress/themes/deploy',
847
856
  };
848
857
 
858
+ // A headless WordPress is installed in this folder of the document root, not at the root itself.
859
+ hosting_deploy_headlessDirectory = 'cms';
860
+
849
861
  async hosting_deploy_callWordpress(kind, params) {
850
862
  return this.executeApiCall({ name: 'wordpress_' + kind, method: 'POST', path: this.hosting_deploy_wordpressEndpoints[kind] }, params);
851
863
  }
@@ -915,6 +927,7 @@ class MCPServer {
915
927
 
916
928
  async hosting_deploy_wordpressExtension(username, domain, type, params) {
917
929
  const isPlugin = type === 'wordpress-plugin';
930
+ const headless = params.headless === true;
918
931
  const directory = path.resolve(params.path);
919
932
  const slug = params.slug !== undefined ? params.slug : this.hosting_deploy_slug(directory);
920
933
  const { files, skipped } = this.hosting_deploy_listFiles(directory);
@@ -924,7 +937,7 @@ class MCPServer {
924
937
 
925
938
  // The files land in a fresh directory; the deploy call then installs from it.
926
939
  const uploadDirName = slug + '-' + this.hosting_deploy_randomSuffix();
927
- const remoteRoot = (isPlugin ? 'wp-content/plugins/' : 'wp-content/themes/') + uploadDirName;
940
+ const remoteRoot = (headless ? this.hosting_deploy_headlessDirectory + '/' : '') + (isPlugin ? 'wp-content/plugins/' : 'wp-content/themes/') + uploadDirName;
928
941
  await this.hosting_deploy_upload(username, domain, files.map((relativePath) => ({
929
942
  absolutePath: path.join(directory, relativePath),
930
943
  relativePath: remoteRoot + '/' + relativePath,
@@ -944,6 +957,7 @@ class MCPServer {
944
957
  slug,
945
958
  files: files.length,
946
959
  ...(isPlugin ? {} : { activated: params.activate === true }),
960
+ ...(headless ? { headless: true } : {}),
947
961
  }, skipped);
948
962
  }
949
963
 
@@ -97,7 +97,7 @@ interface Skill { uri: string; frontmatter: Record<string, unknown>; resources:
97
97
 
98
98
  /**
99
99
  * MCP Server for Hostinger API
100
- * Generated from OpenAPI spec version 2.1.2
100
+ * Generated from OpenAPI spec version 2.1.3
101
101
  */
102
102
  class MCPServer {
103
103
  private readonly name: string;
@@ -680,6 +680,9 @@ class MCPServer {
680
680
  if (resolved === 'wordpress-site' && !databaseDump) {
681
681
  throw new Error('databaseDump (path to a .sql file) is required to import a WordPress site');
682
682
  }
683
+ if (params.headless === true && resolved !== 'wordpress-plugin' && resolved !== 'wordpress-theme') {
684
+ throw new Error('headless is for wordpress-plugin and wordpress-theme deploys only, not ' + resolved);
685
+ }
683
686
  return resolved;
684
687
  }
685
688
 
@@ -860,6 +863,12 @@ class MCPServer {
860
863
  if (params.slug !== undefined && !(typeof params.slug === 'string' && /^[a-z0-9_-]+$/.test(params.slug))) {
861
864
  throw new Error('slug must contain only lower-case letters, digits, "-" and "_"');
862
865
  }
866
+ if (params.headless !== undefined && typeof params.headless !== 'boolean') {
867
+ throw new Error('headless must be a boolean');
868
+ }
869
+ if (params.headless === true && git !== undefined) {
870
+ throw new Error('headless is for wordpress-plugin and wordpress-theme deploys only, which need a local directory, not git');
871
+ }
863
872
  if (git !== undefined && (typeof git !== 'object' || git === null || typeof git.repository !== 'string' || typeof git.branch !== 'string' || git.branch === '')) {
864
873
  throw new Error('git must be an object with repository (owner/name) and branch');
865
874
  }
@@ -883,6 +892,9 @@ class MCPServer {
883
892
  theme: '/api/hosting/v1/accounts/{username}/websites/{domain}/wordpress/themes/deploy',
884
893
  };
885
894
 
895
+ // A headless WordPress is installed in this folder of the document root, not at the root itself.
896
+ private hosting_deploy_headlessDirectory = 'cms';
897
+
886
898
  private async hosting_deploy_callWordpress(kind: string, params: Record<string, any>): Promise<any> {
887
899
  return this.executeApiCall({ name: 'wordpress_' + kind, method: 'POST', path: this.hosting_deploy_wordpressEndpoints[kind] } as any, params);
888
900
  }
@@ -952,6 +964,7 @@ class MCPServer {
952
964
 
953
965
  private async hosting_deploy_wordpressExtension(username: string, domain: string, type: string, params: Record<string, any>): Promise<any> {
954
966
  const isPlugin = type === 'wordpress-plugin';
967
+ const headless = params.headless === true;
955
968
  const directory = path.resolve(params.path);
956
969
  const slug = params.slug !== undefined ? params.slug : this.hosting_deploy_slug(directory);
957
970
  const { files, skipped } = this.hosting_deploy_listFiles(directory);
@@ -961,7 +974,7 @@ class MCPServer {
961
974
 
962
975
  // The files land in a fresh directory; the deploy call then installs from it.
963
976
  const uploadDirName = slug + '-' + this.hosting_deploy_randomSuffix();
964
- const remoteRoot = (isPlugin ? 'wp-content/plugins/' : 'wp-content/themes/') + uploadDirName;
977
+ const remoteRoot = (headless ? this.hosting_deploy_headlessDirectory + '/' : '') + (isPlugin ? 'wp-content/plugins/' : 'wp-content/themes/') + uploadDirName;
965
978
  await this.hosting_deploy_upload(username, domain, files.map((relativePath) => ({
966
979
  absolutePath: path.join(directory, relativePath),
967
980
  relativePath: remoteRoot + '/' + relativePath,
@@ -981,6 +994,7 @@ class MCPServer {
981
994
  slug,
982
995
  files: files.length,
983
996
  ...(isPlugin ? {} : { activated: params.activate === true }),
997
+ ...(headless ? { headless: true } : {}),
984
998
  }, skipped);
985
999
  }
986
1000
 
@@ -9,7 +9,7 @@ export default [
9
9
  "destructiveHint": true
10
10
  },
11
11
  "topic": "hosting",
12
- "description": "Deploy, publish or upload a website to Hostinger web hosting (Shared, Cloud): static HTML, PHP, a nodejs (Node.js) app, a whole WordPress site, or a WordPress plugin or theme, from a local directory, an archive or a GitHub or GitLab repository. It detects what the project is and does the upload, build and Git setup itself: do not call upload or build operations, and do not archive the directory yourself. WARNING: it overwrites the website's contents and cannot be undone; confirm the domain with the user before deploying to a site that already has content. A Node.js build runs on the server: this returns a buildUuid at once, then call hosting_get-deployment until the build state is completed or failed. Static, PHP, plugin and theme deploys are done when this returns; a WordPress site import only starts, and its files are extracted a few minutes later. From Git, pass type (static or nodejs) unless the site already runs a Node.js app or you pass Node.js settings; a static or PHP site deploys the branch now and again on every push; a Node.js site builds the branch now and on every later push, with the settings stored for the site (when none are stored, pass appType and nodeVersion from the project's engines, plus outputDirectory and buildScript if the app has a build step). Git needs GitHub or GitLab connected once in hPanel.",
12
+ "description": "Deploy, publish or upload a website to Hostinger web hosting (Shared, Cloud): static HTML, PHP, a nodejs (Node.js) app, a whole WordPress site, or a WordPress plugin or theme, from a local directory, an archive or a GitHub or GitLab repository. It detects what the project is and does the upload, build and Git setup itself: do not call upload or build operations, and do not archive the directory yourself. WARNING: it overwrites the website's contents and cannot be undone; confirm the domain with the user before deploying to a site that already has content. A Node.js build runs on the server: this returns a buildUuid at once, then call hosting_get-deployment until the build state is completed or failed. For a plugin or theme on a headless WordPress (installed in the cms folder), pass headless: true. Static, PHP, plugin and theme deploys are done when this returns; a WordPress site import only starts, and its files are extracted a few minutes later. From Git, pass type (static or nodejs) unless the site already runs a Node.js app or you pass Node.js settings; a static or PHP site deploys the branch now and again on every push; a Node.js site builds the branch now and on every later push, with the settings stored for the site (when none are stored, pass appType and nodeVersion from the project's engines, plus outputDirectory and buildScript if the app has a build step). Git needs GitHub or GitLab connected once in hPanel.",
13
13
  "method": "",
14
14
  "path": "",
15
15
  "inputSchema": {
@@ -64,6 +64,10 @@ export default [
64
64
  "type": "boolean",
65
65
  "description": "Activate the theme after deployment (WordPress themes only, default: false)"
66
66
  },
67
+ "headless": {
68
+ "type": "boolean",
69
+ "description": "The site runs headless WordPress, installed in the cms folder of the document root: the plugin or theme is uploaded to cms/wp-content/plugins or cms/wp-content/themes and installed there (wordpress-plugin and wordpress-theme only, default: false)"
70
+ },
67
71
  "databaseDump": {
68
72
  "type": "string",
69
73
  "description": "Path to a .sql dump; required for a WordPress site import"
@@ -13501,6 +13505,90 @@ export default [
13501
13505
  ],
13502
13506
  "group": "reach"
13503
13507
  },
13508
+ {
13509
+ "name": "reach_forms_update",
13510
+ "title": "Update form",
13511
+ "annotations": {
13512
+ "title": "Update form",
13513
+ "readOnlyHint": false,
13514
+ "destructiveHint": true,
13515
+ "idempotentHint": true
13516
+ },
13517
+ "description": "Rename a form and/or change its status.\n\nSetting a `draft` or `paused` form to `active` takes it live: its latest saved design is published\nand visitors can submit it. `paused` and `draft` stop the form from accepting submissions. A form is\nnot reachable by visitors until it is taken live. Design changes saved while the form is already\n`active` stay unpublished until the form is paused and set to `active` again. Renaming does not rename\nthe automatic `form:{name}` tag.",
13518
+ "method": "PATCH",
13519
+ "path": "/api/reach/v1/profiles/{profileUuid}/forms/{formUuid}",
13520
+ "inputSchema": {
13521
+ "type": "object",
13522
+ "properties": {
13523
+ "profileUuid": {
13524
+ "type": "string",
13525
+ "description": "Profile uuid parameter"
13526
+ },
13527
+ "formUuid": {
13528
+ "type": "string",
13529
+ "description": "Form uuid parameter"
13530
+ },
13531
+ "name": {
13532
+ "type": "string",
13533
+ "description": "Form name. Letters, digits, spaces and - . ' _ only."
13534
+ },
13535
+ "status": {
13536
+ "type": "string",
13537
+ "description": "`active` takes the form live, `paused` and `draft` stop it accepting submissions.",
13538
+ "enum": [
13539
+ "active",
13540
+ "paused",
13541
+ "draft"
13542
+ ]
13543
+ }
13544
+ },
13545
+ "required": [
13546
+ "profileUuid",
13547
+ "formUuid"
13548
+ ]
13549
+ },
13550
+ "security": [
13551
+ {
13552
+ "apiToken": []
13553
+ }
13554
+ ],
13555
+ "group": "reach"
13556
+ },
13557
+ {
13558
+ "name": "reach_forms_duplicate",
13559
+ "title": "Duplicate form",
13560
+ "annotations": {
13561
+ "title": "Duplicate form",
13562
+ "readOnlyHint": false,
13563
+ "destructiveHint": false
13564
+ },
13565
+ "description": "Copy a form into a new draft form with the same name and design.\n\nThe copy shares the source's automatic `form:{name}` tag; other submitter tags are not copied. The\ncopy is not live until its status is set to `active`.",
13566
+ "method": "POST",
13567
+ "path": "/api/reach/v1/profiles/{profileUuid}/forms/{formUuid}/duplicate",
13568
+ "inputSchema": {
13569
+ "type": "object",
13570
+ "properties": {
13571
+ "profileUuid": {
13572
+ "type": "string",
13573
+ "description": "Profile uuid parameter"
13574
+ },
13575
+ "formUuid": {
13576
+ "type": "string",
13577
+ "description": "Form uuid parameter"
13578
+ }
13579
+ },
13580
+ "required": [
13581
+ "profileUuid",
13582
+ "formUuid"
13583
+ ]
13584
+ },
13585
+ "security": [
13586
+ {
13587
+ "apiToken": []
13588
+ }
13589
+ ],
13590
+ "group": "reach"
13591
+ },
13504
13592
  {
13505
13593
  "name": "reach_forms_list",
13506
13594
  "title": "List forms",
@@ -13526,6 +13614,15 @@ export default [
13526
13614
  "per_page": {
13527
13615
  "type": "integer",
13528
13616
  "description": "Number of items per page"
13617
+ },
13618
+ "status": {
13619
+ "type": "string",
13620
+ "description": "Return only forms with this status.",
13621
+ "enum": [
13622
+ "active",
13623
+ "paused",
13624
+ "draft"
13625
+ ]
13529
13626
  }
13530
13627
  },
13531
13628
  "required": [
@@ -13539,6 +13636,162 @@ export default [
13539
13636
  ],
13540
13637
  "group": "reach"
13541
13638
  },
13639
+ {
13640
+ "name": "reach_forms_create",
13641
+ "title": "Create form",
13642
+ "annotations": {
13643
+ "title": "Create form",
13644
+ "readOnlyHint": false,
13645
+ "destructiveHint": false
13646
+ },
13647
+ "description": "Create an empty draft form.\n\nReach also adds an automatic `form:{name}` tag that every submitter receives. A draft has no design\nand is not reachable by visitors: save a design with the update form template operation, then take\nthe form live by setting its status to `active`. Creating a form does not consume AI credits.",
13648
+ "method": "POST",
13649
+ "path": "/api/reach/v1/profiles/{profileUuid}/forms",
13650
+ "inputSchema": {
13651
+ "type": "object",
13652
+ "properties": {
13653
+ "profileUuid": {
13654
+ "type": "string",
13655
+ "description": "Profile uuid parameter"
13656
+ },
13657
+ "name": {
13658
+ "type": "string",
13659
+ "description": "Form name. Letters, digits, spaces and - . ' _ only."
13660
+ }
13661
+ },
13662
+ "required": [
13663
+ "profileUuid",
13664
+ "name"
13665
+ ]
13666
+ },
13667
+ "security": [
13668
+ {
13669
+ "apiToken": []
13670
+ }
13671
+ ],
13672
+ "group": "reach"
13673
+ },
13674
+ {
13675
+ "name": "reach_forms_add-submitter-tags",
13676
+ "title": "Add form submitter tags",
13677
+ "annotations": {
13678
+ "title": "Add form submitter tags",
13679
+ "readOnlyHint": false,
13680
+ "destructiveHint": false
13681
+ },
13682
+ "description": "Add tags to a form so that every contact who submits it from now on receives them.\n\nA tag the form already has is skipped; an unknown tag is rejected. Contacts who submitted earlier are\nnot tagged.",
13683
+ "method": "POST",
13684
+ "path": "/api/reach/v1/profiles/{profileUuid}/forms/{formUuid}/tags",
13685
+ "inputSchema": {
13686
+ "type": "object",
13687
+ "properties": {
13688
+ "profileUuid": {
13689
+ "type": "string",
13690
+ "description": "Profile uuid parameter"
13691
+ },
13692
+ "formUuid": {
13693
+ "type": "string",
13694
+ "description": "Form uuid parameter"
13695
+ },
13696
+ "tag_uuids": {
13697
+ "type": "array",
13698
+ "description": "tag_uuids parameter",
13699
+ "items": {
13700
+ "type": "string",
13701
+ "description": "tag_uuids parameter"
13702
+ }
13703
+ }
13704
+ },
13705
+ "required": [
13706
+ "profileUuid",
13707
+ "formUuid",
13708
+ "tag_uuids"
13709
+ ]
13710
+ },
13711
+ "security": [
13712
+ {
13713
+ "apiToken": []
13714
+ }
13715
+ ],
13716
+ "group": "reach"
13717
+ },
13718
+ {
13719
+ "name": "reach_forms_remove-submitter-tag",
13720
+ "title": "Remove form submitter tag",
13721
+ "annotations": {
13722
+ "title": "Remove form submitter tag",
13723
+ "readOnlyHint": false,
13724
+ "destructiveHint": true,
13725
+ "idempotentHint": true
13726
+ },
13727
+ "description": "Stop a form from applying a tag to its future submitters.\n\nSucceeds also when the form did not have the tag. Contacts who already received the tag keep it, and\nthe tag itself is not deleted. The automatic `form:{name}` tag cannot be removed and is rejected with\na conflict.",
13728
+ "method": "DELETE",
13729
+ "path": "/api/reach/v1/profiles/{profileUuid}/forms/{formUuid}/tags",
13730
+ "inputSchema": {
13731
+ "type": "object",
13732
+ "properties": {
13733
+ "profileUuid": {
13734
+ "type": "string",
13735
+ "description": "Profile uuid parameter"
13736
+ },
13737
+ "formUuid": {
13738
+ "type": "string",
13739
+ "description": "Form uuid parameter"
13740
+ }
13741
+ },
13742
+ "required": [
13743
+ "profileUuid",
13744
+ "formUuid"
13745
+ ]
13746
+ },
13747
+ "security": [
13748
+ {
13749
+ "apiToken": []
13750
+ }
13751
+ ],
13752
+ "group": "reach"
13753
+ },
13754
+ {
13755
+ "name": "reach_forms_update-template",
13756
+ "title": "Update form template",
13757
+ "annotations": {
13758
+ "title": "Update form template",
13759
+ "readOnlyHint": false,
13760
+ "destructiveHint": true,
13761
+ "idempotentHint": true
13762
+ },
13763
+ "description": "Save `content` as the latest design of a form and return the stored version.\n\nThe HTML is sanitized and, unless the plan allows removing it, the Reach signature is added. Visitors\nsubmit the form with an `email` field (required) and optional `name`, `surname` and `phone`. After\nsanitizing, the design must contain a form container (`data-reach-form`), an email input\n(`data-reach-field=\"email\"`) and a submit button (`data-reach-submit`); otherwise the request fails\nwith `422` and `errors.content` lists `missing_form_container`, `missing_email_field` and/or\n`missing_submit_button`.\n\nA `draft` or `paused` form stays unreachable until its status is set to `active`, which publishes this\ndesign. On a form that is already `active` the saved design is not public until the form is paused and\nset to `active` again. Saving a design does not consume AI credits.",
13764
+ "method": "PATCH",
13765
+ "path": "/api/reach/v1/profiles/{profileUuid}/forms/{formUuid}/template",
13766
+ "inputSchema": {
13767
+ "type": "object",
13768
+ "properties": {
13769
+ "profileUuid": {
13770
+ "type": "string",
13771
+ "description": "Profile uuid parameter"
13772
+ },
13773
+ "formUuid": {
13774
+ "type": "string",
13775
+ "description": "Form uuid parameter"
13776
+ },
13777
+ "content": {
13778
+ "type": "string",
13779
+ "description": "HTML of the form design. After sanitizing it must still contain a form container\n(`data-reach-form`), an email input (`data-reach-field=\"email\"`) and a submit button\n(`data-reach-submit`)."
13780
+ }
13781
+ },
13782
+ "required": [
13783
+ "profileUuid",
13784
+ "formUuid",
13785
+ "content"
13786
+ ]
13787
+ },
13788
+ "security": [
13789
+ {
13790
+ "apiToken": []
13791
+ }
13792
+ ],
13793
+ "group": "reach"
13794
+ },
13542
13795
  {
13543
13796
  "name": "reach_profiles_connected-sending-domain",
13544
13797
  "title": "Get connected sending domain",