diff --git a/packages/backend/src/apps/pushover/assets/favicon.svg b/packages/backend/src/apps/pushover/assets/favicon.svg
new file mode 100644
index 00000000..28492a9e
--- /dev/null
+++ b/packages/backend/src/apps/pushover/assets/favicon.svg
@@ -0,0 +1,7 @@
+
+
diff --git a/packages/backend/src/apps/pushover/auth/index.ts b/packages/backend/src/apps/pushover/auth/index.ts
new file mode 100644
index 00000000..217bee14
--- /dev/null
+++ b/packages/backend/src/apps/pushover/auth/index.ts
@@ -0,0 +1,44 @@
+import verifyCredentials from './verify-credentials';
+import isStillVerified from './is-still-verified';
+
+export default {
+ fields: [
+ {
+ key: 'screenName',
+ label: 'Screen Name',
+ type: 'string' as const,
+ required: true,
+ readOnly: false,
+ value: null,
+ placeholder: null,
+ description:
+ 'Screen name of your connection to be used on Automatisch UI.',
+ clickToCopy: false,
+ },
+ {
+ key: 'userKey',
+ label: 'User Key',
+ type: 'string' as const,
+ required: true,
+ readOnly: false,
+ value: null,
+ placeholder: null,
+ description: null,
+ clickToCopy: false,
+ },
+ {
+ key: 'apiToken',
+ label: 'API 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/pushover/auth/is-still-verified.ts b/packages/backend/src/apps/pushover/auth/is-still-verified.ts
new file mode 100644
index 00000000..66bb963e
--- /dev/null
+++ b/packages/backend/src/apps/pushover/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/pushover/auth/verify-credentials.ts b/packages/backend/src/apps/pushover/auth/verify-credentials.ts
new file mode 100644
index 00000000..3dd9440d
--- /dev/null
+++ b/packages/backend/src/apps/pushover/auth/verify-credentials.ts
@@ -0,0 +1,25 @@
+import { IGlobalVariable } from '@automatisch/types';
+import HttpError from '../../../errors/http';
+
+const verifyCredentials = async ($: IGlobalVariable) => {
+ try {
+ await $.http.post(`/1/users/validate.json`, {
+ token: $.auth.data.apiToken as string,
+ user: $.auth.data.userKey as string,
+ });
+ } catch (error) {
+ const noDeviceError = 'user is valid but has no active devices';
+ const hasNoDeviceError =
+ error.response?.data?.errors?.includes(noDeviceError);
+
+ if (!hasNoDeviceError) {
+ throw new HttpError(error);
+ }
+ }
+
+ await $.auth.set({
+ screenName: $.auth.data.screenName,
+ });
+};
+
+export default verifyCredentials;
diff --git a/packages/backend/src/apps/pushover/index.d.ts b/packages/backend/src/apps/pushover/index.d.ts
new file mode 100644
index 00000000..e69de29b
diff --git a/packages/backend/src/apps/pushover/index.ts b/packages/backend/src/apps/pushover/index.ts
new file mode 100644
index 00000000..212df7d3
--- /dev/null
+++ b/packages/backend/src/apps/pushover/index.ts
@@ -0,0 +1,14 @@
+import defineApp from '../../helpers/define-app';
+import auth from './auth';
+
+export default defineApp({
+ name: 'Pushover',
+ key: 'pushover',
+ baseUrl: 'https://pushover.net',
+ apiBaseUrl: 'https://api.pushover.net',
+ iconUrl: '{BASE_URL}/apps/pushover/assets/favicon.svg',
+ authDocUrl: 'https://automatisch.io/docs/apps/pushover/connection',
+ primaryColor: '249DF1',
+ supportsConnections: true,
+ auth,
+});
diff --git a/packages/docs/pages/.vitepress/config.js b/packages/docs/pages/.vitepress/config.js
index 11e5c795..741200f3 100644
--- a/packages/docs/pages/.vitepress/config.js
+++ b/packages/docs/pages/.vitepress/config.js
@@ -262,6 +262,12 @@ export default defineConfig({
{ text: 'Connection', link: '/apps/postgresql/connection' },
],
},
+ {
+ text: 'Pushover',
+ collapsible: true,
+ collapsed: true,
+ items: [{ text: 'Connection', link: '/apps/pushover/connection' }],
+ },
{
text: 'RSS',
collapsible: true,
diff --git a/packages/docs/pages/apps/pushover/connection.md b/packages/docs/pages/apps/pushover/connection.md
new file mode 100644
index 00000000..0281097a
--- /dev/null
+++ b/packages/docs/pages/apps/pushover/connection.md
@@ -0,0 +1,9 @@
+# Pushover
+
+1. Login to [your account page](https://pushover.net/login) on Pushover.
+2. Copy the **Your User Key** value to the **User Key** field in Automatisch connection page.
+3. Create a new application from [here](https://pushover.net/apps/build) on Pushover.
+4. Copy the **API Token/Key** value to the **API Token** field in Automatisch connection page.
+5. Write any screen name to be displayed in Automatisch.
+6. Click `Submit`.
+7. Start using Pushover integration with Automatisch!
diff --git a/packages/docs/pages/public/favicons/pushover.svg b/packages/docs/pages/public/favicons/pushover.svg
new file mode 100644
index 00000000..28492a9e
--- /dev/null
+++ b/packages/docs/pages/public/favicons/pushover.svg
@@ -0,0 +1,7 @@
+
+