diff --git a/packages/backend/src/apps/hubspot/actions/create-contact/index.ts b/packages/backend/src/apps/hubspot/actions/create-contact/index.ts
new file mode 100644
index 00000000..8c6c6317
--- /dev/null
+++ b/packages/backend/src/apps/hubspot/actions/create-contact/index.ts
@@ -0,0 +1,92 @@
+import defineAction from '../../../../helpers/define-action';
+
+export default defineAction({
+ name: 'Create contact',
+ key: 'createContact',
+ description: `Create contact on user's account.`,
+ arguments: [
+ {
+ label: 'Company',
+ key: 'company',
+ type: 'string' as const,
+ required: false,
+ description: 'company name',
+ variables: true,
+ },
+ {
+ label: 'E-mail',
+ key: 'email',
+ type: 'string' as const,
+ required: false,
+ description: 'Contact email',
+ variables: true,
+ },
+ {
+ label: 'First name',
+ key: 'firstname',
+ type: 'string' as const,
+ required: false,
+ description: 'Contact First name',
+ variables: true,
+ },
+ {
+ label: 'Last name',
+ key: 'lastname',
+ type: 'string' as const,
+ required: false,
+ description: 'Contact Last name',
+ variables: true,
+ },
+ {
+ label: 'Phone',
+ key: 'phone',
+ type: 'string' as const,
+ required: false,
+ description: 'Contact phone number',
+ variables: true,
+ },
+ {
+ label: 'Webiste URL',
+ key: 'website',
+ type: 'string' as const,
+ required: false,
+ description: 'Contact Webiste URL',
+ variables: true,
+ },
+ {
+ label: 'Owner ID',
+ key: 'hubspot_owner_id',
+ type: 'string' as const,
+ required: false,
+ description: 'Contact Owner ID',
+ variables: true,
+ },
+ ],
+
+ async run($) {
+ const company = $.step.parameters.company as string || undefined;
+ const email = $.step.parameters.email as string || undefined;
+ const firstname = $.step.parameters.firstname as string || undefined;
+ const lastname = $.step.parameters.lastname as string || undefined;
+ const phone = $.step.parameters.phone as string || undefined;
+ const website = $.step.parameters.website as string || undefined;
+ const hubspot_owner_id = $.step.parameters.hubspot_owner_id as number || undefined;
+
+ const response = await $.http.post(
+ `crm/v3/objects/contacts`,
+ {
+ properties: {
+ company,
+ email,
+ firstname,
+ lastname,
+ phone,
+ website,
+ hubspot_owner_id,
+ }
+ }
+ );
+
+ $.setActionItem({ raw: response.data });
+ },
+});
diff --git a/packages/backend/src/apps/hubspot/actions/index.ts b/packages/backend/src/apps/hubspot/actions/index.ts
new file mode 100644
index 00000000..fe753ed8
--- /dev/null
+++ b/packages/backend/src/apps/hubspot/actions/index.ts
@@ -0,0 +1,3 @@
+import createContact from './create-contact';
+
+export default [ createContact ];
diff --git a/packages/backend/src/apps/hubspot/assets/favicon.svg b/packages/backend/src/apps/hubspot/assets/favicon.svg
new file mode 100644
index 00000000..c21891fb
--- /dev/null
+++ b/packages/backend/src/apps/hubspot/assets/favicon.svg
@@ -0,0 +1,8 @@
+
+
diff --git a/packages/backend/src/apps/hubspot/auth/index.ts b/packages/backend/src/apps/hubspot/auth/index.ts
new file mode 100644
index 00000000..02064ff5
--- /dev/null
+++ b/packages/backend/src/apps/hubspot/auth/index.ts
@@ -0,0 +1,20 @@
+import verifyCredentials from "./verify-credentials";
+import isStillVerified from "./is-still-verified";
+
+export default {
+ fields: [
+ {
+ key: 'accessToken',
+ label: 'Access Token',
+ type: 'string' as const,
+ required: true,
+ readOnly: false,
+ value: null,
+ placeholder: null,
+ description: null,
+ clickToCopy: false,
+ },
+ ],
+ verifyCredentials,
+ isStillVerified
+};
diff --git a/packages/backend/src/apps/hubspot/auth/is-still-verified.ts b/packages/backend/src/apps/hubspot/auth/is-still-verified.ts
new file mode 100644
index 00000000..4470a643
--- /dev/null
+++ b/packages/backend/src/apps/hubspot/auth/is-still-verified.ts
@@ -0,0 +1,9 @@
+import { IGlobalVariable } from '@automatisch/types';
+import verifyCredentials from "./verify-credentials";
+
+const isStillVerified = async ($: IGlobalVariable) => {
+ await verifyCredentials($);
+ return true;
+};
+
+export default isStillVerified;
diff --git a/packages/backend/src/apps/hubspot/auth/verify-credentials.ts b/packages/backend/src/apps/hubspot/auth/verify-credentials.ts
new file mode 100644
index 00000000..cff860ba
--- /dev/null
+++ b/packages/backend/src/apps/hubspot/auth/verify-credentials.ts
@@ -0,0 +1,12 @@
+import { IGlobalVariable } from '@automatisch/types';
+
+const verifyCredentials = async ($: IGlobalVariable) => {
+ await $.http.get(
+ `/crm/v3/objects/contacts?limit=1`,
+ );
+ await $.auth.set({
+ screenName: $.auth.data?.displayName,
+ });
+};
+
+export default verifyCredentials;
diff --git a/packages/backend/src/apps/hubspot/common/add-auth-header.ts b/packages/backend/src/apps/hubspot/common/add-auth-header.ts
new file mode 100644
index 00000000..d16f394f
--- /dev/null
+++ b/packages/backend/src/apps/hubspot/common/add-auth-header.ts
@@ -0,0 +1,14 @@
+import { TBeforeRequest } from '@automatisch/types';
+
+const addAuthHeader: TBeforeRequest = ($, requestConfig) => {
+ if (requestConfig.additionalProperties?.skipAddingAuthHeader) return requestConfig;
+
+ if ($.auth.data?.accessToken) {
+ const authorizationHeader = `Bearer ${$.auth.data.accessToken}`;
+ requestConfig.headers.Authorization = authorizationHeader;
+ }
+
+ return requestConfig;
+};
+
+export default addAuthHeader;
diff --git a/packages/backend/src/apps/hubspot/index.d.ts b/packages/backend/src/apps/hubspot/index.d.ts
new file mode 100644
index 00000000..e69de29b
diff --git a/packages/backend/src/apps/hubspot/index.ts b/packages/backend/src/apps/hubspot/index.ts
new file mode 100644
index 00000000..3855131c
--- /dev/null
+++ b/packages/backend/src/apps/hubspot/index.ts
@@ -0,0 +1,18 @@
+import defineApp from '../../helpers/define-app';
+import addAuthHeader from './common/add-auth-header';
+import actions from './actions';
+import auth from './auth';
+
+export default defineApp({
+ name: 'Hubspot',
+ key: 'hubspot',
+ iconUrl: '{BASE_URL}/apps/hubspot/assets/favicon.svg',
+ authDocUrl: 'https://developers.hubspot.com/docs/api/crm/contacts',
+ supportsConnections: true,
+ baseUrl: 'https://www.hubspot.com',
+ apiBaseUrl: 'https://api.hubapi.com',
+ primaryColor: '000000',
+ beforeRequest: [addAuthHeader],
+ auth,
+ actions,
+});
diff --git a/packages/docs/pages/.vitepress/config.js b/packages/docs/pages/.vitepress/config.js
index d87539a5..76dc9d9e 100644
--- a/packages/docs/pages/.vitepress/config.js
+++ b/packages/docs/pages/.vitepress/config.js
@@ -271,6 +271,15 @@ export default defineConfig({
{ text: 'Connection', link: '/apps/spotify/connection' },
],
},
+ {
+ text: 'Hubspot',
+ collapsible: true,
+ collapsed: true,
+ items: [
+ { text: 'Actions', link: '/apps/hubspot/actions' },
+ { text: 'Connection', link: '/apps/hubspot/connection' },
+ ],
+ },
{
text: 'Strava',
collapsible: true,
diff --git a/packages/docs/pages/apps/hubspot/actions.md b/packages/docs/pages/apps/hubspot/actions.md
new file mode 100644
index 00000000..f2ae7746
--- /dev/null
+++ b/packages/docs/pages/apps/hubspot/actions.md
@@ -0,0 +1,12 @@
+---
+favicon: /favicons/hubspot.svg
+items:
+ - name: Create a contact
+ desc: Create a contact on user's account.
+---
+
+
+
+
diff --git a/packages/docs/pages/apps/hubspot/connection.md b/packages/docs/pages/apps/hubspot/connection.md
new file mode 100644
index 00000000..df4467b9
--- /dev/null
+++ b/packages/docs/pages/apps/hubspot/connection.md
@@ -0,0 +1,11 @@
+# Spotify
+
+:::info
+This page explains the steps you need to follow to set up the Hubspot connection in Automatisch. If any of the steps are outdated, please let us know!
+:::
+
+1. Create new app
+1. Create new app token
+1. Paste **API TOKEN** value into Automatisch as **Access Token**, respectively.
+1. Click **Submit** button on Automatisch.
+1. Now, you can start using the Spotify connection with Automatisch.
diff --git a/packages/docs/pages/guide/available-apps.md b/packages/docs/pages/guide/available-apps.md
index 63578431..e76f7f3c 100644
--- a/packages/docs/pages/guide/available-apps.md
+++ b/packages/docs/pages/guide/available-apps.md
@@ -28,6 +28,7 @@ The following integrations are currently supported by Automatisch.
- [Slack](/apps/slack/actions)
- [SMTP](/apps/smtp/actions)
- [Spotify](/apps/spotify/actions)
+- [Hubspot](/apps/hubspot/actions)
- [Strava](/apps/strava/actions)
- [Stripe](/apps/stripe/triggers)
- [Telegram](/apps/telegram-bot/actions)
diff --git a/packages/docs/pages/public/favicons/hubspot.svg b/packages/docs/pages/public/favicons/hubspot.svg
new file mode 100644
index 00000000..c21891fb
--- /dev/null
+++ b/packages/docs/pages/public/favicons/hubspot.svg
@@ -0,0 +1,8 @@
+
+