diff --git a/.github/workflows/docker-compose.dev.healthcheck.yml b/.github/workflows/docker-compose.dev.healthcheck.yml
deleted file mode 100644
index 91f17b09c..000000000
--- a/.github/workflows/docker-compose.dev.healthcheck.yml
+++ /dev/null
@@ -1,30 +0,0 @@
-name: docker-compose.dev.yml - Healthcheck
-
-on:
- push:
- branches: ["main"]
- pull_request:
- branches: ["main"]
-
-jobs:
- docker:
- name: Run containers
- runs-on: ubuntu-latest
- env:
- POSTGRES_USER: ${{ secrets.POSTGRES_USER }}
- POSTGRES_PASSWORD: ${{ secrets.POSTGRES_PASSWORD }}
- POSTGRES_DB: ${{ secrets.POSTGRES_DB }}
- DISTRIBUTION: ${{ secrets.DISTRIBUTION }}
- JWT_SECRET: ${{ secrets.JWT_SECRET }}
- REDIS_HOST: ${{ secrets.REDIS_HOST }}
- NEXT_PUBLIC_BACKEND_DOMAIN: ${{ secrets.NEXT_PUBLIC_BACKEND_DOMAIN }}
- NEXT_PUBLIC_MAGIC_LINK_DOMAIN: ${{ secrets.NEXT_PUBLIC_MAGIC_LINK_DOMAIN }}
- NEXT_PUBLIC_STYTCH_PROJECT_ID: ${{ secrets.NEXT_PUBLIC_STYTCH_PROJECT_ID }}
- NEXT_PUBLIC_STYTCH_SECRET: ${{ secrets.NEXT_PUBLIC_STYTCH_SECRET }}
- NEXT_PUBLIC_STYTCH_PROJECT_ENV: ${{ secrets.NEXT_PUBLIC_STYTCH_PROJECT_ENV }}
- NEXT_PUBLIC_STYTCH_PUBLIC_TOKEN: ${{ secrets.NEXT_PUBLIC_STYTCH_PUBLIC_TOKEN }}
- steps:
- - uses: actions/checkout@v3
- - uses: isbang/compose-action@v1.5.1
- with:
- compose-file: "./docker-compose.dev.yml"
\ No newline at end of file
diff --git a/apps/client-ts/src/components/Auth/b2c/LoginWithStytchSDKUI.tsx b/apps/client-ts/src/components/Auth/b2c/LoginWithStytchSDKUI.tsx
index f961ef441..15674fe51 100644
--- a/apps/client-ts/src/components/Auth/b2c/LoginWithStytchSDKUI.tsx
+++ b/apps/client-ts/src/components/Auth/b2c/LoginWithStytchSDKUI.tsx
@@ -4,6 +4,7 @@ import { StytchLogin } from '@stytch/nextjs';
import { StytchLoginConfig, OAuthProviders, Products, StyleConfig, StytchEvent, StytchError } from '@stytch/vanilla-js';
import { getDomainFromWindow } from '@/lib/stytch/urlUtils';
import { Button } from '@/components/ui/button';
+import { Icons } from '@/components/shared/icons';
const sdkStyle: StyleConfig = {
fontFamily: '"Helvetica New", Helvetica, sans-serif',
@@ -31,18 +32,47 @@ const callbackConfig = {
onError: (error: StytchError) => console.log(error),
}
+const getOauthUrl = (provider: string) => {
+ const isTest = process.env.NEXT_PUBLIC_STYTCH_PROJECT_ENV == 'test';
+ const baseStytch = isTest ? "test" : "api"
+ return `https://${baseStytch}.stytch.com/v1/public/oauth/${provider.toLowerCase()}/start?public_token=${process.env.NEXT_PUBLIC_STYTCH_PUBLIC_TOKEN}`;
+}
+
const LoginWithStytchSDKUI = () => {
return (
<>
-
-
+
+
+
+
+
+
+
+
+
+ Or continue with
+
+
+
+
+
>
)
}
diff --git a/apps/client-ts/src/components/shared/icons.tsx b/apps/client-ts/src/components/shared/icons.tsx
new file mode 100644
index 000000000..a0362adcf
--- /dev/null
+++ b/apps/client-ts/src/components/shared/icons.tsx
@@ -0,0 +1,26 @@
+import { LucideProps } from "lucide-react";
+
+
+
+ export const Icons = {
+ gitHub: ({ ...props }: LucideProps) => (
+
+ ),
+ google: ({ ...props }: LucideProps) => (
+
+ )
+ }
\ No newline at end of file
diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml
index 19280187f..4d3ebf949 100644
--- a/docker-compose.dev.yml
+++ b/docker-compose.dev.yml
@@ -66,8 +66,6 @@ services:
JIRA_SERVICE_MGMT_TICKETING_CLIENT_SECRET: ${JIRA_SERVICE_MGMT_TICKETING_CLIENT_SECRET}
LINEAR_TICKETING_CLIENT_ID: ${LINEAR_TICKETING_CLIENT_ID}
LINEAR_TICKETING_CLIENT_SECRET: ${LINEAR_TICKETING_CLIENT_SECRET}
- AFFINITY_CRM_CLIENT_ID: ${AFFINITY_CRM_CLIENT_ID}
- AFFINITY_CRM_CLIENT_SECRET: ${AFFINITY_CRM_CLIENT_SECRET}
ACCELO_CRM_CLIENT_ID: ${ACCELO_CRM_CLIENT_ID}
ACCELO_CRM_CLIENT_SECRET: ${ACCELO_CRM_CLIENT_SECRET}
ACCELO_CRM_SUBDOMAIN: ${ACCELO_CRM_SUBDOMAIN}
@@ -77,13 +75,8 @@ services:
CLOSE_CRM_CLIENT_SECRET: ${CLOSE_CRM_CLIENT_SECRET}
COPPER_CRM_CLIENT_ID: ${COPPER_CRM_CLIENT_ID}
COPPER_CRM_CLIENT_SECRET: ${COPPER_CRM_CLIENT_SECRET}
- INSIGHTLY_CRM_CLIENT_ID: ${INSIGHTLY_CRM_CLIENT_ID}
- INSIGHTLY_CRM_CLIENT_SECRET: ${INSIGHTLY_CRM_CLIENT_SECRET}
KEAP_CRM_CLIENT_ID: ${KEAP_CRM_CLIENT_ID}
KEAP_CRM_CLIENT_SECRET: ${KEAP_CRM_CLIENT_SECRET}
- SUGARCRM_CRM_CLIENT_ID: ${SUGARCRM_CRM_CLIENT_ID}
- SUGARCRM_CRM_CLIENT_SECRET: ${SUGARCRM_CRM_CLIENT_SECRET}
- SUGARCRM_CRM_SUBDOMAIN: ${SUGARCRM_CRM_SUBDOMAIN}
TEAMLEADER_CRM_CLIENT_ID: ${TEAMLEADER_CRM_CLIENT_ID}
TEAMLEADER_CRM_CLIENT_SECRET: ${TEAMLEADER_CRM_CLIENT_SECRET}
TEAMWORK_CRM_CLIENT_ID: ${TEAMWORK_CRM_CLIENT_ID}
@@ -91,6 +84,33 @@ services:
AHA_TICKETING_CLIENT_ID: ${AHA_TICKETING_CLIENT_ID}
AHA_TICKETING_CLIENT_SECRET: ${AHA_TICKETING_CLIENT_SECRET}
AHA_TICKETING_SUBDOMAIN: ${AHA_TICKETING_SUBDOMAIN}
+ WRIKE_TICKETING_CLOUD_CLIENT_ID: ${WRIKE_TICKETING_CLOUD_CLIENT_ID}
+ WRIKE_TICKETING_CLOUD_CLIENT_SECRET: ${WRIKE_TICKETING_CLOUD_CLIENT_SECRET}
+ ASANA_TICKETING_CLOUD_CLIENT_ID: ${ASANA_TICKETING_CLOUD_CLIENT_ID}
+ ASANA_TICKETING_CLOUD_CLIENT_SECRET: ${ASANA_TICKETING_CLOUD_CLIENT_SECRET}
+ PENNYLANE_ACCOUNTING_CLOUD_CLIENT_ID: ${PENNYLANE_ACCOUNTING_CLOUD_CLIENT_ID}
+ PENNYLANE_ACCOUNTING_CLOUD_CLIENT_SECRET: ${PENNYLANE_ACCOUNTING_CLOUD_CLIENT_SECRET}
+ FRESHBOOKS_ACCOUNTING_CLOUD_CLIENT_ID: ${FRESHBOOKS_ACCOUNTING_CLOUD_CLIENT_ID}
+ FRESHBOOKS_ACCOUNTING_CLOUD_CLIENT_SECRET: ${FRESHBOOKS_ACCOUNTING_CLOUD_CLIENT_SECRET}
+ FREEAGENT_ACCOUNTING_CLOUD_CLIENT_ID: ${FREEAGENT_ACCOUNTING_CLOUD_CLIENT_ID}
+ FREEAGENT_ACCOUNTING_CLOUD_CLIENT_SECRET: ${FREEAGENT_ACCOUNTING_CLOUD_CLIENT_SECRET}
+ SAGE_ACCOUNTING_CLOUD_CLIENT_ID: ${SAGE_ACCOUNTING_CLOUD_CLIENT_ID}
+ SAGE_ACCOUNTING_CLOUD_CLIENT_SECRET: ${SAGE_ACCOUNTING_CLOUD_CLIENT_SECRET}
+ MONEYBIRD_ACCOUNTING_CLOUD_CLIENT_ID: ${MONEYBIRD_ACCOUNTING_CLOUD_CLIENT_ID}
+ MONEYBIRD_ACCOUNTING_CLOUD_CLIENT_SECRET: ${MONEYBIRD_ACCOUNTING_CLOUD_CLIENT_SECRET}
+ QUICKBOOKS_ACCOUNTING_CLOUD_CLIENT_ID: ${QUICKBOOKS_ACCOUNTING_CLOUD_CLIENT_ID}
+ QUICKBOOKS_ACCOUNTING_CLOUD_CLIENT_SECRET: ${QUICKBOOKS_ACCOUNTING_CLOUD_CLIENT_SECRET}
+ WAVE_FINANCIAL_ACCOUNTING_CLOUD_CLIENT_ID: ${WAVE_FINANCIAL_ACCOUNTING_CLOUD_CLIENT_ID}
+ WAVE_FINANCIAL_ACCOUNTING_CLOUD_CLIENT_SECRET: ${WAVE_FINANCIAL_ACCOUNTING_CLOUD_CLIENT_SECRET}
+
+
+
+
+
+
+
+
+
restart:
unless-stopped
ports:
diff --git a/docker-compose.source.yml b/docker-compose.source.yml
index 79c4bbef0..a28722d7a 100644
--- a/docker-compose.source.yml
+++ b/docker-compose.source.yml
@@ -91,6 +91,33 @@ services:
AHA_TICKETING_CLIENT_ID: ${AHA_TICKETING_CLIENT_ID}
AHA_TICKETING_CLIENT_SECRET: ${AHA_TICKETING_CLIENT_SECRET}
AHA_TICKETING_SUBDOMAIN: ${AHA_TICKETING_SUBDOMAIN}
+ WRIKE_TICKETING_CLOUD_CLIENT_ID: ${WRIKE_TICKETING_CLOUD_CLIENT_ID}
+ WRIKE_TICKETING_CLOUD_CLIENT_SECRET: ${WRIKE_TICKETING_CLOUD_CLIENT_SECRET}
+ ASANA_TICKETING_CLOUD_CLIENT_ID: ${ASANA_TICKETING_CLOUD_CLIENT_ID}
+ ASANA_TICKETING_CLOUD_CLIENT_SECRET: ${ASANA_TICKETING_CLOUD_CLIENT_SECRET}
+ PENNYLANE_ACCOUNTING_CLOUD_CLIENT_ID: ${PENNYLANE_ACCOUNTING_CLOUD_CLIENT_ID}
+ PENNYLANE_ACCOUNTING_CLOUD_CLIENT_SECRET: ${PENNYLANE_ACCOUNTING_CLOUD_CLIENT_SECRET}
+ FRESHBOOKS_ACCOUNTING_CLOUD_CLIENT_ID: ${FRESHBOOKS_ACCOUNTING_CLOUD_CLIENT_ID}
+ FRESHBOOKS_ACCOUNTING_CLOUD_CLIENT_SECRET: ${FRESHBOOKS_ACCOUNTING_CLOUD_CLIENT_SECRET}
+ FREEAGENT_ACCOUNTING_CLOUD_CLIENT_ID: ${FREEAGENT_ACCOUNTING_CLOUD_CLIENT_ID}
+ FREEAGENT_ACCOUNTING_CLOUD_CLIENT_SECRET: ${FREEAGENT_ACCOUNTING_CLOUD_CLIENT_SECRET}
+ SAGE_ACCOUNTING_CLOUD_CLIENT_ID: ${SAGE_ACCOUNTING_CLOUD_CLIENT_ID}
+ SAGE_ACCOUNTING_CLOUD_CLIENT_SECRET: ${SAGE_ACCOUNTING_CLOUD_CLIENT_SECRET}
+ MONEYBIRD_ACCOUNTING_CLOUD_CLIENT_ID: ${MONEYBIRD_ACCOUNTING_CLOUD_CLIENT_ID}
+ MONEYBIRD_ACCOUNTING_CLOUD_CLIENT_SECRET: ${MONEYBIRD_ACCOUNTING_CLOUD_CLIENT_SECRET}
+ QUICKBOOKS_ACCOUNTING_CLOUD_CLIENT_ID: ${QUICKBOOKS_ACCOUNTING_CLOUD_CLIENT_ID}
+ QUICKBOOKS_ACCOUNTING_CLOUD_CLIENT_SECRET: ${QUICKBOOKS_ACCOUNTING_CLOUD_CLIENT_SECRET}
+ WAVE_FINANCIAL_ACCOUNTING_CLOUD_CLIENT_ID: ${WAVE_FINANCIAL_ACCOUNTING_CLOUD_CLIENT_ID}
+ WAVE_FINANCIAL_ACCOUNTING_CLOUD_CLIENT_SECRET: ${WAVE_FINANCIAL_ACCOUNTING_CLOUD_CLIENT_SECRET}
+
+
+
+
+
+
+
+
+
restart: unless-stopped
ports:
- 3000:3000
diff --git a/docker-compose.yml b/docker-compose.yml
index fb8314689..7501f73ac 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -86,6 +86,33 @@ services:
AHA_TICKETING_CLIENT_ID: ${AHA_TICKETING_CLIENT_ID}
AHA_TICKETING_CLIENT_SECRET: ${AHA_TICKETING_CLIENT_SECRET}
AHA_TICKETING_SUBDOMAIN: ${AHA_TICKETING_SUBDOMAIN}
+ WRIKE_TICKETING_CLOUD_CLIENT_ID: ${WRIKE_TICKETING_CLOUD_CLIENT_ID}
+ WRIKE_TICKETING_CLOUD_CLIENT_SECRET: ${WRIKE_TICKETING_CLOUD_CLIENT_SECRET}
+ ASANA_TICKETING_CLOUD_CLIENT_ID: ${ASANA_TICKETING_CLOUD_CLIENT_ID}
+ ASANA_TICKETING_CLOUD_CLIENT_SECRET: ${ASANA_TICKETING_CLOUD_CLIENT_SECRET}
+ PENNYLANE_ACCOUNTING_CLOUD_CLIENT_ID: ${PENNYLANE_ACCOUNTING_CLOUD_CLIENT_ID}
+ PENNYLANE_ACCOUNTING_CLOUD_CLIENT_SECRET: ${PENNYLANE_ACCOUNTING_CLOUD_CLIENT_SECRET}
+ FRESHBOOKS_ACCOUNTING_CLOUD_CLIENT_ID: ${FRESHBOOKS_ACCOUNTING_CLOUD_CLIENT_ID}
+ FRESHBOOKS_ACCOUNTING_CLOUD_CLIENT_SECRET: ${FRESHBOOKS_ACCOUNTING_CLOUD_CLIENT_SECRET}
+ FREEAGENT_ACCOUNTING_CLOUD_CLIENT_ID: ${FREEAGENT_ACCOUNTING_CLOUD_CLIENT_ID}
+ FREEAGENT_ACCOUNTING_CLOUD_CLIENT_SECRET: ${FREEAGENT_ACCOUNTING_CLOUD_CLIENT_SECRET}
+ SAGE_ACCOUNTING_CLOUD_CLIENT_ID: ${SAGE_ACCOUNTING_CLOUD_CLIENT_ID}
+ SAGE_ACCOUNTING_CLOUD_CLIENT_SECRET: ${SAGE_ACCOUNTING_CLOUD_CLIENT_SECRET}
+ MONEYBIRD_ACCOUNTING_CLOUD_CLIENT_ID: ${MONEYBIRD_ACCOUNTING_CLOUD_CLIENT_ID}
+ MONEYBIRD_ACCOUNTING_CLOUD_CLIENT_SECRET: ${MONEYBIRD_ACCOUNTING_CLOUD_CLIENT_SECRET}
+ QUICKBOOKS_ACCOUNTING_CLOUD_CLIENT_ID: ${QUICKBOOKS_ACCOUNTING_CLOUD_CLIENT_ID}
+ QUICKBOOKS_ACCOUNTING_CLOUD_CLIENT_SECRET: ${QUICKBOOKS_ACCOUNTING_CLOUD_CLIENT_SECRET}
+ WAVE_FINANCIAL_ACCOUNTING_CLOUD_CLIENT_ID: ${WAVE_FINANCIAL_ACCOUNTING_CLOUD_CLIENT_ID}
+ WAVE_FINANCIAL_ACCOUNTING_CLOUD_CLIENT_SECRET: ${WAVE_FINANCIAL_ACCOUNTING_CLOUD_CLIENT_SECRET}
+
+
+
+
+
+
+
+
+
restart:
unless-stopped
ports:
diff --git a/docs/open-source/contributors.mdx b/docs/open-source/contributors.mdx
index 27a73afb3..7940c1e8a 100644
--- a/docs/open-source/contributors.mdx
+++ b/docs/open-source/contributors.mdx
@@ -15,18 +15,23 @@ We made a docker file that builds Panora from sources, specifically to help you
-```bash cp .env.example .env ```
+
+```bash
+cp .env.example .env
+```
+
- ```bash rm -rf node_modules .pnpm-store ./packages/api/dist
- ./packages/api/node_modules ./apps/webapp/node_modules
- ./apps/frontend_snippet/node_modules ```
+ ```bash
+ rm -rf node_modules .pnpm-store ./packages/api/dist ./packages/api/node_modules ./apps/client-ts/node_modules ./apps/embedded-catalog/react/node_modules ./apps/magic-link/node_modules ./packages/shared/dist
+ ```
- ```bash echo -e "node-linker=hoisted\npackage-import-method=clone-or-copy" >
- .npmrc ```
+ ```bash
+ echo -e "node-linker=hoisted\npackage-import-method=clone-or-copy" > .npmrc
+ ```
diff --git a/packages/api/scripts/oauthConnector.js b/packages/api/scripts/oauthConnector.js
index 6e6e1b939..33b572217 100755
--- a/packages/api/scripts/oauthConnector.js
+++ b/packages/api/scripts/oauthConnector.js
@@ -43,7 +43,7 @@ import { LoggerService } from '@@core/logger/logger.service';
import { v4 as uuidv4 } from 'uuid';
import { EnvironmentService } from '@@core/environment/environment.service';
import { EncryptionService } from '@@core/encryption/encryption.service';
-import {
+import {
CallbackParams,
RefreshParams,
I${verticalUpper}ConnectionService,
@@ -56,7 +56,8 @@ import { ConnectionsStrategiesService } from '@@core/connections-strategies/conn
export type ${providerUpper}OAuthResponse = {
access_token: string;
refresh_token: string;
- expires_at: string;
+ expires_in: string;
+ token_type: string;
};
@Injectable()
@@ -126,7 +127,7 @@ export class ${providerUpper}ConnectionService implements I${verticalUpper}Conne
refresh_token: this.cryptoService.encrypt(data.refresh_token),
account_url: "",
expiration_timestamp: new Date(
- new Date().getTime() + Number(data.expires_at) * 1000,
+ new Date().getTime() + Number(data.expires_in) * 1000,
),
status: 'valid',
created_at: new Date(),
@@ -144,7 +145,7 @@ export class ${providerUpper}ConnectionService implements I${verticalUpper}Conne
access_token: this.cryptoService.encrypt(data.access_token),
refresh_token: this.cryptoService.encrypt(data.refresh_token),
expiration_timestamp: new Date(
- new Date().getTime() + Number(data.expires_at) * 1000,
+ new Date().getTime() + Number(data.expires_in) * 1000,
),
status: 'valid',
created_at: new Date(),
@@ -165,15 +166,16 @@ export class ${providerUpper}ConnectionService implements I${verticalUpper}Conne
async handleTokenRefresh(opts: RefreshParams) {
try {
- const { connectionId, refreshToken } = opts;
- const formData = new URLSearchParams({
- grant_type: 'refresh_token',
- refresh_token: this.cryptoService.decrypt(refreshToken),
- });
+ const { connectionId, refreshToken, projectId } = opts;
const CREDENTIALS = (await this.cService.getCredentials(
projectId,
this.type,
)) as OAuth2AuthData;
+
+ const formData = new URLSearchParams({
+ grant_type: 'refresh_token',
+ refresh_token: this.cryptoService.decrypt(refreshToken),
+ });
const res = await axios.post(
"",
@@ -198,7 +200,7 @@ export class ${providerUpper}ConnectionService implements I${verticalUpper}Conne
access_token: this.cryptoService.encrypt(data.access_token),
refresh_token: this.cryptoService.encrypt(data.refresh_token),
expiration_timestamp: new Date(
- new Date().getTime() + Number(data.expires_at) * 1000,
+ new Date().getTime() + Number(data.expires_in) * 1000,
),
},
});
@@ -286,7 +288,7 @@ function addProviderToDockerCompose(provider, vertical, dockerComposePath) {
function handleUpdate(vertical, provider) {
createServiceFile(vertical, provider);
- addProviderToEnvironmentService(provider, envServiceFilePath);
+ //addProviderToEnvironmentService(provider, envServiceFilePath);
for (const path of paths) {
addProviderToDockerCompose(provider, vertical, path);
}
@@ -298,7 +300,7 @@ if (import.meta.url === process.argv[1]) {
const vertical = args[0];
const provider = args[1];
createServiceFile(vertical, provider);
- addProviderToEnvironmentService(provider, envServiceFilePath);
+ //addProviderToEnvironmentService(provider, envServiceFilePath);
for (const path of paths) {
addProviderToDockerCompose(argv.provider, path);
}
diff --git a/packages/api/src/@core/connections/accounting/accounting.connection.module.ts b/packages/api/src/@core/connections/accounting/accounting.connection.module.ts
new file mode 100644
index 000000000..f705017a9
--- /dev/null
+++ b/packages/api/src/@core/connections/accounting/accounting.connection.module.ts
@@ -0,0 +1,41 @@
+import { Module } from '@nestjs/common';
+import { PrismaService } from '@@core/prisma/prisma.service';
+import { LoggerService } from '@@core/logger/logger.service';
+import { WebhookService } from '@@core/webhook/webhook.service';
+import { WebhookModule } from '@@core/webhook/webhook.module';
+import { EnvironmentService } from '@@core/environment/environment.service';
+import { EncryptionService } from '@@core/encryption/encryption.service';
+import { ConnectionsStrategiesService } from '@@core/connections-strategies/connections-strategies.service';
+import { ServiceRegistry } from './services/registry.service';
+import { AccountingConnectionsService } from './services/accounting.connection.service';
+import { PennylaneConnectionService } from './services/pennylane/pennylane.service';
+import { FreeagentConnectionService } from './services/freeagent/freeagent.service';
+import { FreshbooksConnectionService } from './services/freshbooks/freshbooks.service';
+import { MoneybirdConnectionService } from './services/moneybird/moneybird.service';
+import { QuickbooksConnectionService } from './services/quickbooks/quickbooks.service';
+import { SageConnectionService } from './services/sage/sage.service';
+import { WaveFinancialConnectionService } from './services/wave_financial/wave_financial.service';
+
+@Module({
+ imports: [WebhookModule],
+ providers: [
+ AccountingConnectionsService,
+ PrismaService,
+ LoggerService,
+ WebhookService,
+ EnvironmentService,
+ EncryptionService,
+ ServiceRegistry,
+ ConnectionsStrategiesService,
+ //PROVIDERS SERVICES,
+ PennylaneConnectionService,
+ FreeagentConnectionService,
+ FreshbooksConnectionService,
+ MoneybirdConnectionService,
+ QuickbooksConnectionService,
+ SageConnectionService,
+ WaveFinancialConnectionService,
+ ],
+ exports: [AccountingConnectionsService],
+})
+export class AccountingConnectionModule {}
diff --git a/packages/api/src/@core/connections/accounting/services/accounting.connection.service.ts b/packages/api/src/@core/connections/accounting/services/accounting.connection.service.ts
new file mode 100644
index 000000000..82fb92811
--- /dev/null
+++ b/packages/api/src/@core/connections/accounting/services/accounting.connection.service.ts
@@ -0,0 +1,104 @@
+import { Injectable } from '@nestjs/common';
+import { NotFoundError, handleServiceError } from '@@core/utils/errors';
+import { LoggerService } from '@@core/logger/logger.service';
+import { WebhookService } from '@@core/webhook/webhook.service';
+import { connections as Connection } from '@prisma/client';
+import { PrismaService } from '@@core/prisma/prisma.service';
+import { v4 as uuidv4 } from 'uuid';
+import { CallbackParams, RefreshParams } from '../types';
+import { ServiceRegistry } from './registry.service';
+
+@Injectable()
+export class AccountingConnectionsService {
+ constructor(
+ private serviceRegistry: ServiceRegistry,
+ private webhook: WebhookService,
+ private logger: LoggerService,
+ private prisma: PrismaService,
+ ) {
+ this.logger.setContext(AccountingConnectionsService.name);
+ }
+ //STEP 1:[FRONTEND STEP]
+ //create a frontend SDK snippet in which an authorization embedded link is set up so when users click
+ // on it to grant access => they grant US the access and then when confirmed
+ /*const authUrl =
+ 'https://app.hubspot.com/oauth/authorize' +
+ `?client_id=${encodeURIComponent(CLIENT_ID)}` +
+ `&scope=${encodeURIComponent(SCOPES)}` +
+ `&redirect_uri=${encodeURIComponent(REDIRECT_URI)}`;*/ //oauth/callback
+
+ // oauth server calls this redirect callback
+ // WE WOULD HAVE CREATED A DEV ACCOUNT IN THE 5 CRMs (Panora dev account)
+ // we catch the tmp token and swap it against oauth2 server for access/refresh tokens
+ // to perform actions on his behalf
+ // this call pass 1. integrationID 2. CustomerId 3. Panora Api Key
+ async handleAccountingCallBack(
+ projectId: string,
+ linkedUserId: string,
+ providerName: string,
+ code: string,
+ ) {
+ try {
+ const serviceName = providerName.toLowerCase();
+ const service = this.serviceRegistry.getService(serviceName);
+
+ if (!service) {
+ throw new NotFoundError(`Unknown provider, found ${providerName}`);
+ }
+ const callbackOpts: CallbackParams = {
+ linkedUserId: linkedUserId,
+ projectId: projectId,
+ code: code,
+ };
+ const data: Connection = await service.handleCallback(callbackOpts);
+
+ const event = await this.prisma.events.create({
+ data: {
+ id_event: uuidv4(),
+ status: 'success',
+ type: 'connection.created',
+ method: 'GET',
+ url: '/oauth/callback',
+ provider: providerName.toLowerCase(),
+ direction: '0',
+ timestamp: new Date(),
+ id_linked_user: linkedUserId,
+ },
+ });
+ //directly send the webhook
+ await this.webhook.handlePriorityWebhook(
+ data,
+ 'connection.created',
+ projectId,
+ event.id_event,
+ );
+ } catch (error) {
+ handleServiceError(error, this.logger);
+ }
+ }
+
+ async handleAccountingTokensRefresh(
+ connectionId: string,
+ providerName: string,
+ refresh_token: string,
+ id_project: string,
+ account_url?: string,
+ ) {
+ try {
+ const serviceName = providerName.toLowerCase();
+ const service = this.serviceRegistry.getService(serviceName);
+ if (!service) {
+ throw new NotFoundError(`Unknown provider, found ${providerName}`);
+ }
+ const refreshOpts: RefreshParams = {
+ connectionId: connectionId,
+ refreshToken: refresh_token,
+ account_url: account_url,
+ projectId: id_project,
+ };
+ const data = await service.handleTokenRefresh(refreshOpts);
+ } catch (error) {
+ handleServiceError(error, this.logger);
+ }
+ }
+}
diff --git a/packages/api/src/@core/connections/accounting/services/freeagent/freeagent.service.ts b/packages/api/src/@core/connections/accounting/services/freeagent/freeagent.service.ts
new file mode 100644
index 000000000..fc411d48a
--- /dev/null
+++ b/packages/api/src/@core/connections/accounting/services/freeagent/freeagent.service.ts
@@ -0,0 +1,180 @@
+import { Injectable } from '@nestjs/common';
+import axios from 'axios';
+import { PrismaService } from '@@core/prisma/prisma.service';
+import { Action, handleServiceError } from '@@core/utils/errors';
+import { LoggerService } from '@@core/logger/logger.service';
+import { v4 as uuidv4 } from 'uuid';
+import { EnvironmentService } from '@@core/environment/environment.service';
+import { EncryptionService } from '@@core/encryption/encryption.service';
+import {
+ CallbackParams,
+ RefreshParams,
+ IAccountingConnectionService,
+} from '../../types';
+import { ServiceRegistry } from '../registry.service';
+import { AuthStrategy, providersConfig } from '@panora/shared';
+import { OAuth2AuthData, providerToType } from '@panora/shared';
+import { ConnectionsStrategiesService } from '@@core/connections-strategies/connections-strategies.service';
+
+export type FreeagentOAuthResponse = {
+ access_token: string;
+ refresh_token: string;
+ expires_in: string | number;
+ refresh_token_expires_in: number;
+ token_type: string;
+};
+
+@Injectable()
+export class FreeagentConnectionService
+ implements IAccountingConnectionService
+{
+ private readonly type: string;
+
+ constructor(
+ private prisma: PrismaService,
+ private logger: LoggerService,
+ private env: EnvironmentService,
+ private cryptoService: EncryptionService,
+ private registry: ServiceRegistry,
+ private cService: ConnectionsStrategiesService,
+ ) {
+ this.logger.setContext(FreeagentConnectionService.name);
+ this.registry.registerService('freeagent', this);
+ this.type = providerToType('freeagent', 'accounting', AuthStrategy.oauth2);
+ }
+
+ async handleCallback(opts: CallbackParams) {
+ try {
+ const { linkedUserId, projectId, code } = opts;
+ const isNotUnique = await this.prisma.connections.findFirst({
+ where: {
+ id_linked_user: linkedUserId,
+ provider_slug: 'freeagent',
+ vertical: 'accounting',
+ },
+ });
+
+ //reconstruct the redirect URI that was passed in the githubend it must be the same
+ const REDIRECT_URI = `${this.env.getOAuthRredirectBaseUrl()}/connections/oauth/callback`;
+ const CREDENTIALS = (await this.cService.getCredentials(
+ projectId,
+ this.type,
+ )) as OAuth2AuthData;
+
+ const formData = new URLSearchParams({
+ redirect_uri: REDIRECT_URI,
+ code: code,
+ grant_type: 'authorization_code',
+ });
+ const res = await axios.post(
+ 'https://api.freeagent.com/v2/token_endpoint',
+ formData.toString(),
+ {
+ headers: {
+ 'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
+ Authorization: `Basic ${Buffer.from(
+ `${CREDENTIALS.CLIENT_ID}:${CREDENTIALS.CLIENT_SECRET}`,
+ ).toString('base64')}`,
+ },
+ },
+ );
+ const data: FreeagentOAuthResponse = res.data;
+ this.logger.log(
+ 'OAuth credentials : freeagent ticketing ' + JSON.stringify(data),
+ );
+
+ let db_res;
+ const connection_token = uuidv4();
+
+ if (isNotUnique) {
+ db_res = await this.prisma.connections.update({
+ where: {
+ id_connection: isNotUnique.id_connection,
+ },
+ data: {
+ access_token: this.cryptoService.encrypt(data.access_token),
+ refresh_token: this.cryptoService.encrypt(data.refresh_token),
+ account_url:
+ providersConfig['accounting']['freshagent'].urls.apiUrl,
+ expiration_timestamp: new Date(
+ new Date().getTime() + Number(data.expires_in) * 1000,
+ ),
+ status: 'valid',
+ created_at: new Date(),
+ },
+ });
+ } else {
+ db_res = await this.prisma.connections.create({
+ data: {
+ id_connection: uuidv4(),
+ connection_token: connection_token,
+ provider_slug: 'freeagent',
+ vertical: 'accounting',
+ token_type: 'oauth',
+ account_url:
+ providersConfig['accounting']['freshagent'].urls.apiUrl,
+ access_token: this.cryptoService.encrypt(data.access_token),
+ refresh_token: this.cryptoService.encrypt(data.refresh_token),
+ expiration_timestamp: new Date(
+ new Date().getTime() + Number(data.expires_in) * 1000,
+ ),
+ status: 'valid',
+ created_at: new Date(),
+ projects: {
+ connect: { id_project: projectId },
+ },
+ linked_users: {
+ connect: { id_linked_user: linkedUserId },
+ },
+ },
+ });
+ }
+ return db_res;
+ } catch (error) {
+ handleServiceError(error, this.logger, 'freeagent', Action.oauthCallback);
+ }
+ }
+
+ async handleTokenRefresh(opts: RefreshParams) {
+ try {
+ const { connectionId, refreshToken, projectId } = opts;
+ const formData = new URLSearchParams({
+ grant_type: 'refresh_token',
+ refresh_token: this.cryptoService.decrypt(refreshToken),
+ });
+ const CREDENTIALS = (await this.cService.getCredentials(
+ projectId,
+ this.type,
+ )) as OAuth2AuthData;
+
+ const res = await axios.post(
+ 'https://api.freeagent.com/v2/token_endpoint',
+ formData.toString(),
+ {
+ headers: {
+ 'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
+ Authorization: `Basic ${Buffer.from(
+ `${CREDENTIALS.CLIENT_ID}:${CREDENTIALS.CLIENT_SECRET}`,
+ ).toString('base64')}`,
+ },
+ },
+ );
+ const data: FreeagentOAuthResponse = res.data;
+ await this.prisma.connections.update({
+ where: {
+ id_connection: connectionId,
+ },
+ data: {
+ access_token: this.cryptoService.encrypt(data.access_token),
+ refresh_token: this.cryptoService.encrypt(data.refresh_token),
+ expiration_timestamp: new Date(
+ new Date().getTime() + Number(data.expires_in) * 1000,
+ ),
+ },
+ });
+ this.logger.log('OAuth credentials updated : freeagent ');
+ } catch (error) {
+ handleServiceError(error, this.logger, 'freeagent', Action.oauthRefresh);
+ }
+ }
+}
diff --git a/packages/api/src/@core/connections/accounting/services/freshbooks/freshbooks.service.ts b/packages/api/src/@core/connections/accounting/services/freshbooks/freshbooks.service.ts
new file mode 100644
index 000000000..23f0f5e22
--- /dev/null
+++ b/packages/api/src/@core/connections/accounting/services/freshbooks/freshbooks.service.ts
@@ -0,0 +1,183 @@
+import { Injectable } from '@nestjs/common';
+import axios from 'axios';
+import { PrismaService } from '@@core/prisma/prisma.service';
+import { Action, handleServiceError } from '@@core/utils/errors';
+import { LoggerService } from '@@core/logger/logger.service';
+import { v4 as uuidv4 } from 'uuid';
+import { EnvironmentService } from '@@core/environment/environment.service';
+import { EncryptionService } from '@@core/encryption/encryption.service';
+import {
+ CallbackParams,
+ RefreshParams,
+ IAccountingConnectionService,
+} from '../../types';
+import { ServiceRegistry } from '../registry.service';
+import { AuthStrategy, providersConfig } from '@panora/shared';
+import { OAuth2AuthData, providerToType } from '@panora/shared';
+import { ConnectionsStrategiesService } from '@@core/connections-strategies/connections-strategies.service';
+
+export type FreshbooksOAuthResponse = {
+ access_token: string;
+ refresh_token: string;
+ expires_in: string;
+ created_at: number;
+ token_type: string;
+};
+
+@Injectable()
+export class FreshbooksConnectionService
+ implements IAccountingConnectionService
+{
+ private readonly type: string;
+
+ constructor(
+ private prisma: PrismaService,
+ private logger: LoggerService,
+ private env: EnvironmentService,
+ private cryptoService: EncryptionService,
+ private registry: ServiceRegistry,
+ private cService: ConnectionsStrategiesService,
+ ) {
+ this.logger.setContext(FreshbooksConnectionService.name);
+ this.registry.registerService('freshbooks', this);
+ this.type = providerToType('freshbooks', 'accounting', AuthStrategy.oauth2);
+ }
+
+ async handleCallback(opts: CallbackParams) {
+ try {
+ const { linkedUserId, projectId, code } = opts;
+ const isNotUnique = await this.prisma.connections.findFirst({
+ where: {
+ id_linked_user: linkedUserId,
+ provider_slug: 'freshbooks',
+ vertical: 'accounting',
+ },
+ });
+
+ //reconstruct the redirect URI that was passed in the githubend it must be the same
+ const REDIRECT_URI = `${this.env.getOAuthRredirectBaseUrl()}/connections/oauth/callback`;
+ const CREDENTIALS = (await this.cService.getCredentials(
+ projectId,
+ this.type,
+ )) as OAuth2AuthData;
+
+ const formData = new URLSearchParams({
+ client_id: CREDENTIALS.CLIENT_ID,
+ client_secret: CREDENTIALS.CLIENT_SECRET,
+ redirect_uri: REDIRECT_URI,
+ code: code,
+ grant_type: 'authorization_code',
+ });
+ const res = await axios.post(
+ 'https://api.freshbooks.com/auth/oauth/token',
+ formData.toString(),
+ {
+ headers: {
+ 'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
+ },
+ },
+ );
+ const data: FreshbooksOAuthResponse = res.data;
+ this.logger.log(
+ 'OAuth credentials : freshbooks ticketing ' + JSON.stringify(data),
+ );
+
+ let db_res;
+ const connection_token = uuidv4();
+
+ if (isNotUnique) {
+ db_res = await this.prisma.connections.update({
+ where: {
+ id_connection: isNotUnique.id_connection,
+ },
+ data: {
+ access_token: this.cryptoService.encrypt(data.access_token),
+ refresh_token: this.cryptoService.encrypt(data.refresh_token),
+ account_url: providersConfig['accounting']['freshbooks'].urls.apiUrl,
+ expiration_timestamp: new Date(
+ new Date().getTime() + Number(data.expires_in) * 1000,
+ ),
+ status: 'valid',
+ created_at: new Date(),
+ },
+ });
+ } else {
+ db_res = await this.prisma.connections.create({
+ data: {
+ id_connection: uuidv4(),
+ connection_token: connection_token,
+ provider_slug: 'freshbooks',
+ vertical: 'accounting',
+ token_type: 'oauth',
+ account_url: providersConfig['accounting']['freshbooks'].urls.apiUrl,
+ access_token: this.cryptoService.encrypt(data.access_token),
+ refresh_token: this.cryptoService.encrypt(data.refresh_token),
+ expiration_timestamp: new Date(
+ new Date().getTime() + Number(data.expires_in) * 1000,
+ ),
+ status: 'valid',
+ created_at: new Date(),
+ projects: {
+ connect: { id_project: projectId },
+ },
+ linked_users: {
+ connect: { id_linked_user: linkedUserId },
+ },
+ },
+ });
+ }
+ return db_res;
+ } catch (error) {
+ handleServiceError(
+ error,
+ this.logger,
+ 'freshbooks',
+ Action.oauthCallback,
+ );
+ }
+ }
+
+ async handleTokenRefresh(opts: RefreshParams) {
+ try {
+ const { connectionId, refreshToken, projectId } = opts;
+
+ const CREDENTIALS = (await this.cService.getCredentials(
+ projectId,
+ this.type,
+ )) as OAuth2AuthData;
+
+ const formData = new URLSearchParams({
+ client_id: CREDENTIALS.CLIENT_ID,
+ client_secret: CREDENTIALS.CLIENT_SECRET,
+ grant_type: 'refresh_token',
+ refresh_token: this.cryptoService.decrypt(refreshToken),
+ });
+
+ const res = await axios.post(
+ 'https://api.freshbooks.com/auth/oauth/token',
+ formData.toString(),
+ {
+ headers: {
+ 'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
+ },
+ },
+ );
+ const data: FreshbooksOAuthResponse = res.data;
+ await this.prisma.connections.update({
+ where: {
+ id_connection: connectionId,
+ },
+ data: {
+ access_token: this.cryptoService.encrypt(data.access_token),
+ refresh_token: this.cryptoService.encrypt(data.refresh_token),
+ expiration_timestamp: new Date(
+ new Date().getTime() + Number(data.expires_in) * 1000,
+ ),
+ },
+ });
+ this.logger.log('OAuth credentials updated : freshbooks ');
+ } catch (error) {
+ handleServiceError(error, this.logger, 'freshbooks', Action.oauthRefresh);
+ }
+ }
+}
diff --git a/packages/api/src/@core/connections/crm/services/insightly/insightly.service.ts b/packages/api/src/@core/connections/accounting/services/moneybird/moneybird.service.ts
similarity index 68%
rename from packages/api/src/@core/connections/crm/services/insightly/insightly.service.ts
rename to packages/api/src/@core/connections/accounting/services/moneybird/moneybird.service.ts
index 223b95cbc..4d2085d3a 100644
--- a/packages/api/src/@core/connections/crm/services/insightly/insightly.service.ts
+++ b/packages/api/src/@core/connections/accounting/services/moneybird/moneybird.service.ts
@@ -9,21 +9,26 @@ import { EncryptionService } from '@@core/encryption/encryption.service';
import {
CallbackParams,
RefreshParams,
- ICrmConnectionService,
+ IAccountingConnectionService,
} from '../../types';
import { ServiceRegistry } from '../registry.service';
+import { AuthStrategy, providersConfig } from '@panora/shared';
import { OAuth2AuthData, providerToType } from '@panora/shared';
-import { AuthStrategy } from '@panora/shared';
import { ConnectionsStrategiesService } from '@@core/connections-strategies/connections-strategies.service';
-export type InsightlyOAuthResponse = {
+export type MoneybirdOAuthResponse = {
access_token: string;
refresh_token: string;
- expires_at: string;
+ expires_in: string;
+ token_type: string;
+ scope: string;
+ created_at: number;
};
@Injectable()
-export class InsightlyConnectionService implements ICrmConnectionService {
+export class MoneybirdConnectionService
+ implements IAccountingConnectionService
+{
private readonly type: string;
constructor(
@@ -34,9 +39,9 @@ export class InsightlyConnectionService implements ICrmConnectionService {
private registry: ServiceRegistry,
private cService: ConnectionsStrategiesService,
) {
- this.logger.setContext(InsightlyConnectionService.name);
- this.registry.registerService('insightly', this);
- this.type = providerToType('insightly', 'crm', AuthStrategy.oauth2);
+ this.logger.setContext(MoneybirdConnectionService.name);
+ this.registry.registerService('moneybird', this);
+ this.type = providerToType('moneybird', 'accounting', AuthStrategy.oauth2);
}
async handleCallback(opts: CallbackParams) {
@@ -45,8 +50,8 @@ export class InsightlyConnectionService implements ICrmConnectionService {
const isNotUnique = await this.prisma.connections.findFirst({
where: {
id_linked_user: linkedUserId,
- provider_slug: `insightly`,
- vertical: 'crm',
+ provider_slug: 'moneybird',
+ vertical: 'accounting',
},
});
@@ -64,15 +69,18 @@ export class InsightlyConnectionService implements ICrmConnectionService {
code: code,
grant_type: 'authorization_code',
});
- //const subdomain = 'panora';
- const res = await axios.post('', formData.toString(), {
- headers: {
- 'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
+ const res = await axios.post(
+ ' https://moneybird.com/oauth/token',
+ formData.toString(),
+ {
+ headers: {
+ 'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
+ },
},
- });
- const data: InsightlyOAuthResponse = res.data;
+ );
+ const data: MoneybirdOAuthResponse = res.data;
this.logger.log(
- 'OAuth credentials : insightly ticketing ' + JSON.stringify(data),
+ 'OAuth credentials : moneybird ticketing ' + JSON.stringify(data),
);
let db_res;
@@ -86,9 +94,9 @@ export class InsightlyConnectionService implements ICrmConnectionService {
data: {
access_token: this.cryptoService.encrypt(data.access_token),
refresh_token: this.cryptoService.encrypt(data.refresh_token),
- account_url: '',
+ account_url: providersConfig['accounting']['moneybird'].urls.apiUrl,
expiration_timestamp: new Date(
- new Date().getTime() + Number(data.expires_at) * 1000,
+ new Date().getTime() + Number(data.expires_in) * 1000,
),
status: 'valid',
created_at: new Date(),
@@ -99,14 +107,14 @@ export class InsightlyConnectionService implements ICrmConnectionService {
data: {
id_connection: uuidv4(),
connection_token: connection_token,
- provider_slug: 'insightly',
- vertical: 'crm',
+ provider_slug: 'moneybird',
+ vertical: 'accounting',
token_type: 'oauth',
- account_url: '',
+ account_url: providersConfig['accounting']['moneybird'].urls.apiUrl,
access_token: this.cryptoService.encrypt(data.access_token),
refresh_token: this.cryptoService.encrypt(data.refresh_token),
expiration_timestamp: new Date(
- new Date().getTime() + Number(data.expires_at) * 1000,
+ new Date().getTime() + Number(data.expires_in) * 1000,
),
status: 'valid',
created_at: new Date(),
@@ -121,30 +129,33 @@ export class InsightlyConnectionService implements ICrmConnectionService {
}
return db_res;
} catch (error) {
- handleServiceError(error, this.logger, 'insightly', Action.oauthCallback);
+ handleServiceError(error, this.logger, 'moneybird', Action.oauthCallback);
}
}
async handleTokenRefresh(opts: RefreshParams) {
try {
const { connectionId, refreshToken, projectId } = opts;
- const formData = new URLSearchParams({
- grant_type: 'refresh_token',
- refresh_token: this.cryptoService.decrypt(refreshToken),
- });
const CREDENTIALS = (await this.cService.getCredentials(
projectId,
this.type,
)) as OAuth2AuthData;
-
- const subdomain = 'panora';
- const res = await axios.post('', formData.toString(), {
- headers: {
- 'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
- Authorization: `Basic JHt0aGlzLmVudi5nZXRgSW5zaWdodGx5U2VjcmV0YCgpLkNMSUVOVF9JRH06JHsKICAgICAgICAgICAgICAgIHRoaXMuZW52LmdldGBJbnNpZ2h0bHlTZWNyZXRgKCkuQ0xJRU5UX1NFQ1JFVAogICAgICAgICAgICAgIH0=`,
- },
+ const formData = new URLSearchParams({
+ client_id: CREDENTIALS.CLIENT_ID,
+ client_SECRET: CREDENTIALS.CLIENT_SECRET,
+ grant_type: 'refresh_token',
+ refresh_token: this.cryptoService.decrypt(refreshToken),
});
- const data: InsightlyOAuthResponse = res.data;
+ const res = await axios.post(
+ 'https://moneybird.com/oauth/token',
+ formData.toString(),
+ {
+ headers: {
+ 'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
+ },
+ },
+ );
+ const data: MoneybirdOAuthResponse = res.data;
await this.prisma.connections.update({
where: {
id_connection: connectionId,
@@ -153,13 +164,13 @@ export class InsightlyConnectionService implements ICrmConnectionService {
access_token: this.cryptoService.encrypt(data.access_token),
refresh_token: this.cryptoService.encrypt(data.refresh_token),
expiration_timestamp: new Date(
- new Date().getTime() + Number(data.expires_at) * 1000,
+ new Date().getTime() + Number(data.expires_in) * 1000,
),
},
});
- this.logger.log('OAuth credentials updated : insightly ');
+ this.logger.log('OAuth credentials updated : moneybird ');
} catch (error) {
- handleServiceError(error, this.logger, 'insightly', Action.oauthRefresh);
+ handleServiceError(error, this.logger, 'moneybird', Action.oauthRefresh);
}
}
}
diff --git a/packages/api/src/@core/connections/accounting/services/pennylane/pennylane.service.ts b/packages/api/src/@core/connections/accounting/services/pennylane/pennylane.service.ts
new file mode 100644
index 000000000..af1827251
--- /dev/null
+++ b/packages/api/src/@core/connections/accounting/services/pennylane/pennylane.service.ts
@@ -0,0 +1,177 @@
+import { Injectable } from '@nestjs/common';
+import axios from 'axios';
+import { PrismaService } from '@@core/prisma/prisma.service';
+import { Action, handleServiceError } from '@@core/utils/errors';
+import { LoggerService } from '@@core/logger/logger.service';
+import { v4 as uuidv4 } from 'uuid';
+import { EnvironmentService } from '@@core/environment/environment.service';
+import { EncryptionService } from '@@core/encryption/encryption.service';
+import {
+ CallbackParams,
+ RefreshParams,
+ IAccountingConnectionService,
+} from '../../types';
+import { ServiceRegistry } from '../registry.service';
+import { AuthStrategy, providersConfig } from '@panora/shared';
+import { OAuth2AuthData, providerToType } from '@panora/shared';
+import { ConnectionsStrategiesService } from '@@core/connections-strategies/connections-strategies.service';
+
+export type PennylaneOAuthResponse = {
+ access_token: string;
+ refresh_token: string;
+ expires_in: number;
+ token_type: string;
+};
+
+@Injectable()
+export class PennylaneConnectionService
+ implements IAccountingConnectionService
+{
+ private readonly type: string;
+
+ constructor(
+ private prisma: PrismaService,
+ private logger: LoggerService,
+ private env: EnvironmentService,
+ private cryptoService: EncryptionService,
+ private registry: ServiceRegistry,
+ private cService: ConnectionsStrategiesService,
+ ) {
+ this.logger.setContext(PennylaneConnectionService.name);
+ this.registry.registerService('pennylane', this);
+ this.type = providerToType('pennylane', 'accounting', AuthStrategy.oauth2);
+ }
+
+ async handleCallback(opts: CallbackParams) {
+ try {
+ const { linkedUserId, projectId, code } = opts;
+ const isNotUnique = await this.prisma.connections.findFirst({
+ where: {
+ id_linked_user: linkedUserId,
+ provider_slug: 'pennylane',
+ vertical: 'accounting',
+ },
+ });
+
+ //reconstruct the redirect URI that was passed in the githubend it must be the same
+ const REDIRECT_URI = `${this.env.getOAuthRredirectBaseUrl()}/connections/oauth/callback`;
+ const CREDENTIALS = (await this.cService.getCredentials(
+ projectId,
+ this.type,
+ )) as OAuth2AuthData;
+
+ const formData = new URLSearchParams({
+ client_id: CREDENTIALS.CLIENT_ID,
+ client_secret: CREDENTIALS.CLIENT_SECRET,
+ redirect_uri: REDIRECT_URI,
+ code: code,
+ grant_type: 'authorization_code',
+ });
+ const res = await axios.post(
+ 'https://app.pennylane.com/oauth/token',
+ formData.toString(),
+ {
+ headers: {
+ 'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
+ },
+ },
+ );
+ const data: PennylaneOAuthResponse = res.data;
+ this.logger.log(
+ 'OAuth credentials : pennylane ticketing ' + JSON.stringify(data),
+ );
+
+ let db_res;
+ const connection_token = uuidv4();
+
+ if (isNotUnique) {
+ db_res = await this.prisma.connections.update({
+ where: {
+ id_connection: isNotUnique.id_connection,
+ },
+ data: {
+ access_token: this.cryptoService.encrypt(data.access_token),
+ refresh_token: this.cryptoService.encrypt(data.refresh_token),
+ account_url: providersConfig['accounting']['pennylane'].urls.apiUrl,
+ expiration_timestamp: new Date(
+ new Date().getTime() + Number(data.expires_in) * 1000,
+ ),
+ status: 'valid',
+ created_at: new Date(),
+ },
+ });
+ } else {
+ db_res = await this.prisma.connections.create({
+ data: {
+ id_connection: uuidv4(),
+ connection_token: connection_token,
+ provider_slug: 'pennylane',
+ vertical: 'accounting',
+ token_type: 'oauth',
+ account_url: providersConfig['accounting']['pennylane'].urls.apiUrl,
+ access_token: this.cryptoService.encrypt(data.access_token),
+ refresh_token: this.cryptoService.encrypt(data.refresh_token),
+ expiration_timestamp: new Date(
+ new Date().getTime() + Number(data.expires_in) * 1000,
+ ),
+ status: 'valid',
+ created_at: new Date(),
+ projects: {
+ connect: { id_project: projectId },
+ },
+ linked_users: {
+ connect: { id_linked_user: linkedUserId },
+ },
+ },
+ });
+ }
+ return db_res;
+ } catch (error) {
+ handleServiceError(error, this.logger, 'pennylane', Action.oauthCallback);
+ }
+ }
+
+ async handleTokenRefresh(opts: RefreshParams) {
+ try {
+ const { connectionId, refreshToken, projectId } = opts;
+
+ const CREDENTIALS = (await this.cService.getCredentials(
+ projectId,
+ this.type,
+ )) as OAuth2AuthData;
+
+ const formData = new URLSearchParams({
+ client_id: CREDENTIALS.CLIENT_ID,
+ client_secret: CREDENTIALS.CLIENT_SECRET,
+ grant_type: 'refresh_token',
+ refresh_token: this.cryptoService.decrypt(refreshToken),
+ });
+ const res = await axios.post(
+ 'https://app.pennylane.com/oauth/token',
+ formData.toString(),
+ {
+ headers: {
+ 'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
+ Authorization: `Basic Q1JFREVOVElBTFMuQ0xJRU5UX0lEfTokewogICAgICAgICAgICAgICAgICBDUkVERU5USUFMUy5DTElFTlRfU0VDUkVUCiAgICAgICAgICAgICAgfQ==`,
+ },
+ },
+ );
+ const data: PennylaneOAuthResponse = res.data;
+ await this.prisma.connections.update({
+ where: {
+ id_connection: connectionId,
+ },
+ data: {
+ access_token: this.cryptoService.encrypt(data.access_token),
+ refresh_token: this.cryptoService.encrypt(data.refresh_token),
+ expiration_timestamp: new Date(
+ new Date().getTime() + Number(data.expires_in) * 1000,
+ ),
+ },
+ });
+ this.logger.log('OAuth credentials updated : pennylane ');
+ } catch (error) {
+ handleServiceError(error, this.logger, 'pennylane', Action.oauthRefresh);
+ }
+ }
+}
diff --git a/packages/api/src/@core/connections/accounting/services/quickbooks/quickbooks.service.ts b/packages/api/src/@core/connections/accounting/services/quickbooks/quickbooks.service.ts
new file mode 100644
index 000000000..76b24e868
--- /dev/null
+++ b/packages/api/src/@core/connections/accounting/services/quickbooks/quickbooks.service.ts
@@ -0,0 +1,179 @@
+import { Injectable } from '@nestjs/common';
+import axios from 'axios';
+import { PrismaService } from '@@core/prisma/prisma.service';
+import { Action, handleServiceError } from '@@core/utils/errors';
+import { LoggerService } from '@@core/logger/logger.service';
+import { v4 as uuidv4 } from 'uuid';
+import { EnvironmentService } from '@@core/environment/environment.service';
+import { EncryptionService } from '@@core/encryption/encryption.service';
+import {
+ CallbackParams,
+ RefreshParams,
+ IAccountingConnectionService,
+} from '../../types';
+import { ServiceRegistry } from '../registry.service';
+import { AuthStrategy, providersConfig } from '@panora/shared';
+import { OAuth2AuthData, providerToType } from '@panora/shared';
+import { ConnectionsStrategiesService } from '@@core/connections-strategies/connections-strategies.service';
+
+export type QuickbooksOAuthResponse = {
+ access_token: string;
+ refresh_token: string;
+ expires_in: string;
+ token_type: string;
+ x_refresh_token_expires_in: number;
+};
+
+@Injectable()
+export class QuickbooksConnectionService
+ implements IAccountingConnectionService
+{
+ private readonly type: string;
+
+ constructor(
+ private prisma: PrismaService,
+ private logger: LoggerService,
+ private env: EnvironmentService,
+ private cryptoService: EncryptionService,
+ private registry: ServiceRegistry,
+ private cService: ConnectionsStrategiesService,
+ ) {
+ this.logger.setContext(QuickbooksConnectionService.name);
+ this.registry.registerService('quickbooks', this);
+ this.type = providerToType('quickbooks', 'accounting', AuthStrategy.oauth2);
+ }
+
+ async handleCallback(opts: CallbackParams) {
+ try {
+ const { linkedUserId, projectId, code } = opts;
+ const isNotUnique = await this.prisma.connections.findFirst({
+ where: {
+ id_linked_user: linkedUserId,
+ provider_slug: 'quickbooks',
+ vertical: 'accounting',
+ },
+ });
+
+ //reconstruct the redirect URI that was passed in the githubend it must be the same
+ const REDIRECT_URI = `${this.env.getOAuthRredirectBaseUrl()}/connections/oauth/callback`;
+ const CREDENTIALS = (await this.cService.getCredentials(
+ projectId,
+ this.type,
+ )) as OAuth2AuthData;
+
+ const formData = new URLSearchParams({
+ redirect_uri: REDIRECT_URI,
+ code: code,
+ grant_type: 'authorization_code',
+ });
+ const res = await axios.post(
+ 'https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer',
+ formData.toString(),
+ {
+ headers: {
+ 'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
+ Authorization: `Basic ${Buffer.from(
+ `${CREDENTIALS.CLIENT_ID}:${CREDENTIALS.CLIENT_SECRET}`,
+ ).toString('base64')}`,
+ },
+ },
+ );
+ const data: QuickbooksOAuthResponse = res.data;
+ this.logger.log(
+ 'OAuth credentials : quickbooks ticketing ' + JSON.stringify(data),
+ );
+
+ let db_res;
+ const connection_token = uuidv4();
+
+ if (isNotUnique) {
+ db_res = await this.prisma.connections.update({
+ where: {
+ id_connection: isNotUnique.id_connection,
+ },
+ data: {
+ access_token: this.cryptoService.encrypt(data.access_token),
+ refresh_token: this.cryptoService.encrypt(data.refresh_token),
+ account_url: providersConfig['accounting']['quickbooks'].urls.apiUrl,
+ expiration_timestamp: new Date(
+ new Date().getTime() + Number(data.expires_in) * 1000,
+ ),
+ status: 'valid',
+ created_at: new Date(),
+ },
+ });
+ } else {
+ db_res = await this.prisma.connections.create({
+ data: {
+ id_connection: uuidv4(),
+ connection_token: connection_token,
+ provider_slug: 'quickbooks',
+ vertical: 'accounting',
+ token_type: 'oauth',
+ account_url: providersConfig['accounting']['quickbooks'].urls.apiUrl,
+ access_token: this.cryptoService.encrypt(data.access_token),
+ refresh_token: this.cryptoService.encrypt(data.refresh_token),
+ expiration_timestamp: new Date(
+ new Date().getTime() + Number(data.expires_in) * 1000,
+ ),
+ status: 'valid',
+ created_at: new Date(),
+ projects: {
+ connect: { id_project: projectId },
+ },
+ linked_users: {
+ connect: { id_linked_user: linkedUserId },
+ },
+ },
+ });
+ }
+ return db_res;
+ } catch (error) {
+ handleServiceError(
+ error,
+ this.logger,
+ 'quickbooks',
+ Action.oauthCallback,
+ );
+ }
+ }
+
+ async handleTokenRefresh(opts: RefreshParams) {
+ try {
+ const { connectionId, refreshToken, projectId } = opts;
+ const formData = new URLSearchParams({
+ grant_type: 'refresh_token',
+ refresh_token: this.cryptoService.decrypt(refreshToken),
+ });
+ const CREDENTIALS = (await this.cService.getCredentials(
+ projectId,
+ this.type,
+ )) as OAuth2AuthData;
+
+ const res = await axios.post('', formData.toString(), {
+ headers: {
+ 'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
+ Authorization: `Basic ${Buffer.from(
+ `${CREDENTIALS.CLIENT_ID}:${CREDENTIALS.CLIENT_SECRET}`,
+ ).toString('base64')}`,
+ },
+ });
+ const data: QuickbooksOAuthResponse = res.data;
+ await this.prisma.connections.update({
+ where: {
+ id_connection: connectionId,
+ },
+ data: {
+ access_token: this.cryptoService.encrypt(data.access_token),
+ refresh_token: this.cryptoService.encrypt(data.refresh_token),
+ expiration_timestamp: new Date(
+ new Date().getTime() + Number(data.expires_in) * 1000,
+ ),
+ },
+ });
+ this.logger.log('OAuth credentials updated : quickbooks ');
+ } catch (error) {
+ handleServiceError(error, this.logger, 'quickbooks', Action.oauthRefresh);
+ }
+ }
+}
diff --git a/packages/api/src/@core/connections/accounting/services/registry.service.ts b/packages/api/src/@core/connections/accounting/services/registry.service.ts
new file mode 100644
index 000000000..3125b3a83
--- /dev/null
+++ b/packages/api/src/@core/connections/accounting/services/registry.service.ts
@@ -0,0 +1,23 @@
+import { Injectable } from '@nestjs/common';
+import { IAccountingConnectionService } from '../types';
+
+@Injectable()
+export class ServiceRegistry {
+ private serviceMap: Map;
+
+ constructor() {
+ this.serviceMap = new Map();
+ }
+
+ registerService(serviceKey: string, service: IAccountingConnectionService) {
+ this.serviceMap.set(serviceKey, service);
+ }
+
+ getService(integrationId: string): IAccountingConnectionService {
+ const service = this.serviceMap.get(integrationId);
+ if (!service) {
+ throw new Error(`Service not found for integration ID: ${integrationId}`);
+ }
+ return service;
+ }
+}
diff --git a/packages/api/src/@core/connections/crm/services/sugarcrm/sugarcrm.service.ts b/packages/api/src/@core/connections/accounting/services/sage/sage.service.ts
similarity index 77%
rename from packages/api/src/@core/connections/crm/services/sugarcrm/sugarcrm.service.ts
rename to packages/api/src/@core/connections/accounting/services/sage/sage.service.ts
index 9cf4ce982..f29cb1b03 100644
--- a/packages/api/src/@core/connections/crm/services/sugarcrm/sugarcrm.service.ts
+++ b/packages/api/src/@core/connections/accounting/services/sage/sage.service.ts
@@ -9,25 +9,25 @@ import { EncryptionService } from '@@core/encryption/encryption.service';
import {
CallbackParams,
RefreshParams,
- ICrmConnectionService,
+ IAccountingConnectionService,
} from '../../types';
import { ServiceRegistry } from '../registry.service';
+import { AuthStrategy, providersConfig } from '@panora/shared';
import { OAuth2AuthData, providerToType } from '@panora/shared';
-import { AuthStrategy } from '@panora/shared';
import { ConnectionsStrategiesService } from '@@core/connections-strategies/connections-strategies.service';
-export type SugarcrmOAuthResponse = {
+export type SageOAuthResponse = {
access_token: string;
+ refresh_token: string;
+ refresh_token_expires_in: number;
expires_in: number;
- token_type: string;
scope: string;
- refresh_token: string;
- refresh_expires_in: number;
- download_token: string;
+ token_type: string;
+ requested_by_id: string;
};
@Injectable()
-export class SugarcrmConnectionService implements ICrmConnectionService {
+export class SageConnectionService implements IAccountingConnectionService {
private readonly type: string;
constructor(
@@ -38,9 +38,9 @@ export class SugarcrmConnectionService implements ICrmConnectionService {
private registry: ServiceRegistry,
private cService: ConnectionsStrategiesService,
) {
- this.logger.setContext(SugarcrmConnectionService.name);
- this.registry.registerService('sugarcrm', this);
- this.type = providerToType('sugarcrm', 'crm', AuthStrategy.oauth2);
+ this.logger.setContext(SageConnectionService.name);
+ this.registry.registerService('sage', this);
+ this.type = providerToType('sage', 'accounting', AuthStrategy.oauth2);
}
async handleCallback(opts: CallbackParams) {
@@ -49,8 +49,8 @@ export class SugarcrmConnectionService implements ICrmConnectionService {
const isNotUnique = await this.prisma.connections.findFirst({
where: {
id_linked_user: linkedUserId,
- provider_slug: `sugarcrm`,
- vertical: 'crm',
+ provider_slug: 'sage',
+ vertical: 'accounting',
},
});
@@ -64,14 +64,12 @@ export class SugarcrmConnectionService implements ICrmConnectionService {
const formData = new URLSearchParams({
client_id: CREDENTIALS.CLIENT_ID,
client_secret: CREDENTIALS.CLIENT_SECRET,
- grant_type: 'password',
- username: '',
- password: '',
- platform: 'custom',
+ redirect_uri: REDIRECT_URI,
+ code: code,
+ grant_type: 'authorization_code',
});
- //const subdomain = 'panora';
const res = await axios.post(
- `${CREDENTIALS.SUBDOMAIN!}/rest/v11/oauth2/token`,
+ 'https://oauth.accounting.sage.com/token',
formData.toString(),
{
headers: {
@@ -79,9 +77,9 @@ export class SugarcrmConnectionService implements ICrmConnectionService {
},
},
);
- const data: SugarcrmOAuthResponse = res.data;
+ const data: SageOAuthResponse = res.data;
this.logger.log(
- 'OAuth credentials : sugarcrm ticketing ' + JSON.stringify(data),
+ 'OAuth credentials : sage ticketing ' + JSON.stringify(data),
);
let db_res;
@@ -95,7 +93,7 @@ export class SugarcrmConnectionService implements ICrmConnectionService {
data: {
access_token: this.cryptoService.encrypt(data.access_token),
refresh_token: this.cryptoService.encrypt(data.refresh_token),
- account_url: '',
+ account_url: providersConfig['accounting']['sage'].urls.apiUrl,
expiration_timestamp: new Date(
new Date().getTime() + Number(data.expires_in) * 1000,
),
@@ -108,10 +106,10 @@ export class SugarcrmConnectionService implements ICrmConnectionService {
data: {
id_connection: uuidv4(),
connection_token: connection_token,
- provider_slug: 'sugarcrm',
- vertical: 'crm',
+ provider_slug: 'sage',
+ vertical: 'accounting',
token_type: 'oauth',
- account_url: '',
+ account_url: providersConfig['accounting']['sage'].urls.apiUrl,
access_token: this.cryptoService.encrypt(data.access_token),
refresh_token: this.cryptoService.encrypt(data.refresh_token),
expiration_timestamp: new Date(
@@ -130,7 +128,7 @@ export class SugarcrmConnectionService implements ICrmConnectionService {
}
return db_res;
} catch (error) {
- handleServiceError(error, this.logger, 'sugarcrm', Action.oauthCallback);
+ handleServiceError(error, this.logger, 'sage', Action.oauthCallback);
}
}
@@ -146,12 +144,11 @@ export class SugarcrmConnectionService implements ICrmConnectionService {
client_id: CREDENTIALS.CLIENT_ID,
client_secret: CREDENTIALS.CLIENT_SECRET,
grant_type: 'refresh_token',
- platform: 'custom',
refresh_token: this.cryptoService.decrypt(refreshToken),
});
- const subdomain = 'panora';
+
const res = await axios.post(
- `${CREDENTIALS.SUBDOMAIN!}/rest/v11/oauth2/token`,
+ 'https://oauth.accounting.sage.com/toke',
formData.toString(),
{
headers: {
@@ -159,7 +156,7 @@ export class SugarcrmConnectionService implements ICrmConnectionService {
},
},
);
- const data: SugarcrmOAuthResponse = res.data;
+ const data: SageOAuthResponse = res.data;
await this.prisma.connections.update({
where: {
id_connection: connectionId,
@@ -172,9 +169,9 @@ export class SugarcrmConnectionService implements ICrmConnectionService {
),
},
});
- this.logger.log('OAuth credentials updated : sugarcrm ');
+ this.logger.log('OAuth credentials updated : sage ');
} catch (error) {
- handleServiceError(error, this.logger, 'sugarcrm', Action.oauthRefresh);
+ handleServiceError(error, this.logger, 'sage', Action.oauthRefresh);
}
}
}
diff --git a/packages/api/src/@core/connections/accounting/services/wave_financial/wave_financial.service.ts b/packages/api/src/@core/connections/accounting/services/wave_financial/wave_financial.service.ts
new file mode 100644
index 000000000..80194129b
--- /dev/null
+++ b/packages/api/src/@core/connections/accounting/services/wave_financial/wave_financial.service.ts
@@ -0,0 +1,196 @@
+import { Injectable } from '@nestjs/common';
+import axios from 'axios';
+import { PrismaService } from '@@core/prisma/prisma.service';
+import { Action, handleServiceError } from '@@core/utils/errors';
+import { LoggerService } from '@@core/logger/logger.service';
+import { v4 as uuidv4 } from 'uuid';
+import { EnvironmentService } from '@@core/environment/environment.service';
+import { EncryptionService } from '@@core/encryption/encryption.service';
+import {
+ CallbackParams,
+ RefreshParams,
+ IAccountingConnectionService,
+} from '../../types';
+import { ServiceRegistry } from '../registry.service';
+import { AuthStrategy, providersConfig } from '@panora/shared';
+import { OAuth2AuthData, providerToType } from '@panora/shared';
+import { ConnectionsStrategiesService } from '@@core/connections-strategies/connections-strategies.service';
+
+export type WaveFinancialOAuthResponse = {
+ access_token: string;
+ refresh_token: string;
+ expires_in: number | string;
+ token_type: string;
+ scope: string;
+ userId: string;
+ businessId: string;
+};
+
+@Injectable()
+export class WaveFinancialConnectionService
+ implements IAccountingConnectionService
+{
+ private readonly type: string;
+
+ constructor(
+ private prisma: PrismaService,
+ private logger: LoggerService,
+ private env: EnvironmentService,
+ private cryptoService: EncryptionService,
+ private registry: ServiceRegistry,
+ private cService: ConnectionsStrategiesService,
+ ) {
+ this.logger.setContext(WaveFinancialConnectionService.name);
+ this.registry.registerService('wave_financial', this);
+ this.type = providerToType(
+ 'wave_financial',
+ 'accounting',
+ AuthStrategy.oauth2,
+ );
+ }
+
+ async handleCallback(opts: CallbackParams) {
+ try {
+ const { linkedUserId, projectId, code } = opts;
+ const isNotUnique = await this.prisma.connections.findFirst({
+ where: {
+ id_linked_user: linkedUserId,
+ provider_slug: 'wave_financial',
+ vertical: 'accounting',
+ },
+ });
+
+ //reconstruct the redirect URI that was passed in the githubend it must be the same
+ const REDIRECT_URI = `${this.env.getOAuthRredirectBaseUrl()}/connections/oauth/callback`;
+ const CREDENTIALS = (await this.cService.getCredentials(
+ projectId,
+ this.type,
+ )) as OAuth2AuthData;
+
+ const formData = new URLSearchParams({
+ client_id: CREDENTIALS.CLIENT_ID,
+ client_secret: CREDENTIALS.CLIENT_SECRET,
+ redirect_uri: REDIRECT_URI,
+ code: code,
+ grant_type: 'authorization_code',
+ });
+ const res = await axios.post(
+ 'https://api.waveapps.com/oauth2/token/',
+ formData.toString(),
+ {
+ headers: {
+ 'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
+ },
+ },
+ );
+ const data: WaveFinancialOAuthResponse = res.data;
+ this.logger.log(
+ 'OAuth credentials : wave_financial ticketing ' + JSON.stringify(data),
+ );
+
+ let db_res;
+ const connection_token = uuidv4();
+
+ if (isNotUnique) {
+ db_res = await this.prisma.connections.update({
+ where: {
+ id_connection: isNotUnique.id_connection,
+ },
+ data: {
+ access_token: this.cryptoService.encrypt(data.access_token),
+ refresh_token: this.cryptoService.encrypt(data.refresh_token),
+ account_url: providersConfig['accounting']['wave_financial'].urls.apiUrl,
+ expiration_timestamp: new Date(
+ new Date().getTime() + Number(data.expires_in) * 1000,
+ ),
+ status: 'valid',
+ created_at: new Date(),
+ },
+ });
+ } else {
+ db_res = await this.prisma.connections.create({
+ data: {
+ id_connection: uuidv4(),
+ connection_token: connection_token,
+ provider_slug: 'wave_financial',
+ vertical: 'accounting',
+ token_type: 'oauth',
+ account_url: providersConfig['accounting']['wave_financial'].urls.apiUrl,
+ access_token: this.cryptoService.encrypt(data.access_token),
+ refresh_token: this.cryptoService.encrypt(data.refresh_token),
+ expiration_timestamp: new Date(
+ new Date().getTime() + Number(data.expires_in) * 1000,
+ ),
+ status: 'valid',
+ created_at: new Date(),
+ projects: {
+ connect: { id_project: projectId },
+ },
+ linked_users: {
+ connect: { id_linked_user: linkedUserId },
+ },
+ },
+ });
+ }
+ return db_res;
+ } catch (error) {
+ handleServiceError(
+ error,
+ this.logger,
+ 'wave_financial',
+ Action.oauthCallback,
+ );
+ }
+ }
+
+ async handleTokenRefresh(opts: RefreshParams) {
+ try {
+ const { connectionId, refreshToken, projectId } = opts;
+
+ const CREDENTIALS = (await this.cService.getCredentials(
+ projectId,
+ this.type,
+ )) as OAuth2AuthData;
+
+ const REDIRECT_URI = `${this.env.getOAuthRredirectBaseUrl()}/connections/oauth/callback`;
+
+ const formData = new URLSearchParams({
+ grant_type: 'refresh_token',
+ refresh_token: this.cryptoService.decrypt(refreshToken),
+ client_id: CREDENTIALS.CLIENT_ID,
+ client_secret: CREDENTIALS.CLIENT_SECRET,
+ redirect_uri: REDIRECT_URI,
+ });
+ const res = await axios.post(
+ 'https://api.waveapps.com/oauth2/token/',
+ formData.toString(),
+ {
+ headers: {
+ 'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
+ },
+ },
+ );
+ const data: WaveFinancialOAuthResponse = res.data;
+ await this.prisma.connections.update({
+ where: {
+ id_connection: connectionId,
+ },
+ data: {
+ access_token: this.cryptoService.encrypt(data.access_token),
+ refresh_token: this.cryptoService.encrypt(data.refresh_token),
+ expiration_timestamp: new Date(
+ new Date().getTime() + Number(data.expires_in) * 1000,
+ ),
+ },
+ });
+ this.logger.log('OAuth credentials updated : wave_financial ');
+ } catch (error) {
+ handleServiceError(
+ error,
+ this.logger,
+ 'wave_financial',
+ Action.oauthRefresh,
+ );
+ }
+ }
+}
diff --git a/packages/api/src/@core/connections/accounting/types/index.ts b/packages/api/src/@core/connections/accounting/types/index.ts
new file mode 100644
index 000000000..d16f0330e
--- /dev/null
+++ b/packages/api/src/@core/connections/accounting/types/index.ts
@@ -0,0 +1,19 @@
+import { connections as Connection } from '@prisma/client';
+
+export type CallbackParams = {
+ linkedUserId: string;
+ projectId: string;
+ code: string;
+};
+
+export type RefreshParams = {
+ connectionId: string;
+ refreshToken: string;
+ account_url?: string;
+ projectId: string;
+};
+
+export interface IAccountingConnectionService {
+ handleCallback(opts: CallbackParams): Promise;
+ handleTokenRefresh(opts: RefreshParams): Promise;
+}
diff --git a/packages/api/src/@core/connections/connections.controller.ts b/packages/api/src/@core/connections/connections.controller.ts
index d271abcbd..d7562ba42 100644
--- a/packages/api/src/@core/connections/connections.controller.ts
+++ b/packages/api/src/@core/connections/connections.controller.ts
@@ -7,6 +7,7 @@ import { PrismaService } from '@@core/prisma/prisma.service';
import { ApiOperation, ApiQuery, ApiResponse, ApiTags } from '@nestjs/swagger';
import { TicketingConnectionsService } from './ticketing/services/ticketing.connection.service';
import { ProviderVertical } from '@panora/shared';
+import { AccountingConnectionsService } from './accounting/services/accounting.connection.service';
export type StateDataType = {
projectId: string;
@@ -22,6 +23,7 @@ export class ConnectionsController {
constructor(
private readonly crmConnectionsService: CrmConnectionsService,
private readonly ticketingConnectionsService: TicketingConnectionsService,
+ private readonly accountingConnectionsService: AccountingConnectionsService,
private logger: LoggerService,
private prisma: PrismaService,
) {
@@ -70,6 +72,12 @@ export class ConnectionsController {
case ProviderVertical.ATS:
break;
case ProviderVertical.Accounting:
+ this.accountingConnectionsService.handleAccountingCallBack(
+ projectId,
+ linkedUserId,
+ providerName,
+ code,
+ );
break;
case ProviderVertical.FileStorage:
break;
diff --git a/packages/api/src/@core/connections/connections.module.ts b/packages/api/src/@core/connections/connections.module.ts
index 308c8abc8..85cd4b220 100644
--- a/packages/api/src/@core/connections/connections.module.ts
+++ b/packages/api/src/@core/connections/connections.module.ts
@@ -4,11 +4,20 @@ import { ConnectionsController } from './connections.controller';
import { LoggerService } from '@@core/logger/logger.service';
import { PrismaService } from '@@core/prisma/prisma.service';
import { TicketingConnectionModule } from './ticketing/ticketing.connection.module';
+import { AccountingConnectionModule } from './accounting/accounting.connection.module';
@Module({
controllers: [ConnectionsController],
- imports: [CrmConnectionModule, TicketingConnectionModule],
+ imports: [
+ CrmConnectionModule,
+ TicketingConnectionModule,
+ AccountingConnectionModule,
+ ],
providers: [LoggerService, PrismaService],
- exports: [CrmConnectionModule, TicketingConnectionModule],
+ exports: [
+ CrmConnectionModule,
+ TicketingConnectionModule,
+ AccountingConnectionModule,
+ ],
})
export class ConnectionsModule {}
diff --git a/packages/api/src/@core/connections/crm/services/accelo/accelo.service.ts b/packages/api/src/@core/connections/crm/services/accelo/accelo.service.ts
index 956ec833f..d4c6a33ae 100644
--- a/packages/api/src/@core/connections/crm/services/accelo/accelo.service.ts
+++ b/packages/api/src/@core/connections/crm/services/accelo/accelo.service.ts
@@ -12,7 +12,11 @@ import { EnvironmentService } from '@@core/environment/environment.service';
import { EncryptionService } from '@@core/encryption/encryption.service';
import { ServiceRegistry } from '../registry.service';
import { LoggerService } from '@@core/logger/logger.service';
-import { OAuth2AuthData, providerToType } from '@panora/shared';
+import {
+ OAuth2AuthData,
+ providersConfig,
+ providerToType,
+} from '@panora/shared';
import { AuthStrategy } from '@panora/shared';
import { ConnectionsStrategiesService } from '@@core/connections-strategies/connections-strategies.service';
@@ -68,7 +72,6 @@ export class AcceloConnectionService implements ICrmConnectionService {
redirect_uri: REDIRECT_URI,
code: code,
});
- //const subdomain = 'panora'; //TODO: if custom oauth then get the actual domain from customer
const res = await axios.post(
`${CREDENTIALS.SUBDOMAIN}/oauth2/v0/token`,
formData.toString(),
@@ -87,6 +90,9 @@ export class AcceloConnectionService implements ICrmConnectionService {
// Saving the token of customer inside db
let db_res;
const connection_token = uuidv4();
+ //get the right BASE URL API
+ const BASE_API_URL =
+ CREDENTIALS.SUBDOMAIN + providersConfig['crm']['accelo'].urls.apiUrl;
if (isNotUnique) {
// Update existing connection
@@ -96,7 +102,7 @@ export class AcceloConnectionService implements ICrmConnectionService {
},
data: {
access_token: this.cryptoService.encrypt(data.access_token),
- account_url: CREDENTIALS.SUBDOMAIN!,
+ account_url: BASE_API_URL,
expiration_timestamp: new Date(
new Date().getTime() + data.expires_in * 1000,
),
@@ -113,7 +119,7 @@ export class AcceloConnectionService implements ICrmConnectionService {
provider_slug: 'accelo',
vertical: 'crm',
token_type: 'oauth',
- account_url: CREDENTIALS.SUBDOMAIN!,
+ account_url: BASE_API_URL,
access_token: this.cryptoService.encrypt(data.access_token),
expiration_timestamp: new Date(
new Date().getTime() + data.expires_in * 1000,
@@ -151,7 +157,7 @@ export class AcceloConnectionService implements ICrmConnectionService {
)) as OAuth2AuthData;
const res = await axios.post(
- `${CREDENTIALS.SUBDOMAIN!}/oauth2/v0/token`,
+ `${CREDENTIALS.SUBDOMAIN}/oauth2/v0/token`,
formData.toString(),
{
headers: {
diff --git a/packages/api/src/@core/connections/crm/services/attio/attio.service.ts b/packages/api/src/@core/connections/crm/services/attio/attio.service.ts
index b87665972..565d209e6 100644
--- a/packages/api/src/@core/connections/crm/services/attio/attio.service.ts
+++ b/packages/api/src/@core/connections/crm/services/attio/attio.service.ts
@@ -12,7 +12,11 @@ import { EnvironmentService } from '@@core/environment/environment.service';
import { EncryptionService } from '@@core/encryption/encryption.service';
import { ServiceRegistry } from '../registry.service';
import { LoggerService } from '@@core/logger/logger.service';
-import { OAuth2AuthData, providerToType } from '@panora/shared';
+import {
+ OAuth2AuthData,
+ providersConfig,
+ providerToType,
+} from '@panora/shared';
import { AuthStrategy } from '@panora/shared';
import { ConnectionsStrategiesService } from '@@core/connections-strategies/connections-strategies.service';
@@ -104,6 +108,7 @@ export class AttioConnectionService implements ICrmConnectionService {
provider_slug: 'attio',
vertical: 'crm',
token_type: 'oauth',
+ account_url: providersConfig['crm']['attio'].urls.apiUrl,
access_token: this.cryptoService.encrypt(data.access_token),
status: 'valid',
created_at: new Date(),
diff --git a/packages/api/src/@core/connections/crm/services/capsule/capsule.service.ts b/packages/api/src/@core/connections/crm/services/capsule/capsule.service.ts
index f1a0973cd..d49062919 100644
--- a/packages/api/src/@core/connections/crm/services/capsule/capsule.service.ts
+++ b/packages/api/src/@core/connections/crm/services/capsule/capsule.service.ts
@@ -12,7 +12,11 @@ import {
ICrmConnectionService,
} from '../../types';
import { ServiceRegistry } from '../registry.service';
-import { OAuth2AuthData, providerToType } from '@panora/shared';
+import {
+ OAuth2AuthData,
+ providersConfig,
+ providerToType,
+} from '@panora/shared';
import { AuthStrategy } from '@panora/shared';
import { ConnectionsStrategiesService } from '@@core/connections-strategies/connections-strategies.service';
@@ -90,7 +94,7 @@ export class CapsuleConnectionService implements ICrmConnectionService {
data: {
access_token: this.cryptoService.encrypt(data.access_token),
refresh_token: this.cryptoService.encrypt(data.refresh_token),
- account_url: '',
+ account_url: providersConfig['crm']['capsule'].urls.apiUrl,
expiration_timestamp: new Date(
new Date().getTime() + Number(data.expires_in) * 1000,
),
@@ -106,7 +110,7 @@ export class CapsuleConnectionService implements ICrmConnectionService {
provider_slug: 'capsule',
vertical: 'crm',
token_type: 'oauth',
- account_url: '',
+ account_url: providersConfig['crm']['capsule'].urls.apiUrl,
access_token: this.cryptoService.encrypt(data.access_token),
refresh_token: this.cryptoService.encrypt(data.refresh_token),
expiration_timestamp: new Date(
diff --git a/packages/api/src/@core/connections/crm/services/close/close.service.ts b/packages/api/src/@core/connections/crm/services/close/close.service.ts
index 173266254..57da7967c 100644
--- a/packages/api/src/@core/connections/crm/services/close/close.service.ts
+++ b/packages/api/src/@core/connections/crm/services/close/close.service.ts
@@ -12,7 +12,11 @@ import {
ICrmConnectionService,
} from '../../types';
import { ServiceRegistry } from '../registry.service';
-import { OAuth2AuthData, providerToType } from '@panora/shared';
+import {
+ OAuth2AuthData,
+ providersConfig,
+ providerToType,
+} from '@panora/shared';
import { AuthStrategy } from '@panora/shared';
import { ConnectionsStrategiesService } from '@@core/connections-strategies/connections-strategies.service';
@@ -94,7 +98,7 @@ export class CloseConnectionService implements ICrmConnectionService {
data: {
access_token: this.cryptoService.encrypt(data.access_token),
refresh_token: this.cryptoService.encrypt(data.refresh_token),
- account_url: '',
+ account_url: providersConfig['crm']['close'].urls.apiUrl,
expiration_timestamp: new Date(
new Date().getTime() + Number(data.expires_in) * 1000,
),
@@ -110,7 +114,7 @@ export class CloseConnectionService implements ICrmConnectionService {
provider_slug: 'close',
vertical: 'crm',
token_type: 'oauth',
- account_url: '',
+ account_url: providersConfig['crm']['close'].urls.apiUrl,
access_token: this.cryptoService.encrypt(data.access_token),
refresh_token: this.cryptoService.encrypt(data.refresh_token),
expiration_timestamp: new Date(
diff --git a/packages/api/src/@core/connections/crm/services/copper/copper.service.ts b/packages/api/src/@core/connections/crm/services/copper/copper.service.ts
index 260eabca1..42dfa4202 100644
--- a/packages/api/src/@core/connections/crm/services/copper/copper.service.ts
+++ b/packages/api/src/@core/connections/crm/services/copper/copper.service.ts
@@ -12,7 +12,11 @@ import {
ICrmConnectionService,
} from '../../types';
import { ServiceRegistry } from '../registry.service';
-import { OAuth2AuthData, providerToType } from '@panora/shared';
+import {
+ OAuth2AuthData,
+ providersConfig,
+ providerToType,
+} from '@panora/shared';
import { AuthStrategy } from '@panora/shared';
import { ConnectionsStrategiesService } from '@@core/connections-strategies/connections-strategies.service';
@@ -100,7 +104,7 @@ export class CopperConnectionService implements ICrmConnectionService {
provider_slug: 'copper',
vertical: 'crm',
token_type: 'oauth',
- account_url: '',
+ account_url: providersConfig['crm']['copper'].urls.apiUrl,
access_token: this.cryptoService.encrypt(data.access_token),
status: 'valid',
created_at: new Date(),
diff --git a/packages/api/src/@core/connections/crm/services/hubspot/hubspot.service.ts b/packages/api/src/@core/connections/crm/services/hubspot/hubspot.service.ts
index 657183b37..576a8c519 100644
--- a/packages/api/src/@core/connections/crm/services/hubspot/hubspot.service.ts
+++ b/packages/api/src/@core/connections/crm/services/hubspot/hubspot.service.ts
@@ -12,7 +12,11 @@ import { v4 as uuidv4 } from 'uuid';
import { EnvironmentService } from '@@core/environment/environment.service';
import { EncryptionService } from '@@core/encryption/encryption.service';
import { ServiceRegistry } from '../registry.service';
-import { OAuth2AuthData, providerToType } from '@panora/shared';
+import {
+ OAuth2AuthData,
+ providersConfig,
+ providerToType,
+} from '@panora/shared';
import { AuthStrategy } from '@panora/shared';
import { ConnectionsStrategiesService } from '@@core/connections-strategies/connections-strategies.service';
@@ -107,6 +111,7 @@ export class HubspotConnectionService implements ICrmConnectionService {
provider_slug: 'hubspot',
vertical: 'crm',
token_type: 'oauth',
+ account_url: providersConfig['crm']['hubspot'].urls.apiUrl,
access_token: this.cryptoService.encrypt(data.access_token),
refresh_token: this.cryptoService.encrypt(data.refresh_token),
expiration_timestamp: new Date(
diff --git a/packages/api/src/@core/connections/crm/services/keap/keap.service.ts b/packages/api/src/@core/connections/crm/services/keap/keap.service.ts
index 4c23b26e8..66772aa8a 100644
--- a/packages/api/src/@core/connections/crm/services/keap/keap.service.ts
+++ b/packages/api/src/@core/connections/crm/services/keap/keap.service.ts
@@ -12,7 +12,11 @@ import {
ICrmConnectionService,
} from '../../types';
import { ServiceRegistry } from '../registry.service';
-import { OAuth2AuthData, providerToType } from '@panora/shared';
+import {
+ OAuth2AuthData,
+ providersConfig,
+ providerToType,
+} from '@panora/shared';
import { AuthStrategy } from '@panora/shared';
import { ConnectionsStrategiesService } from '@@core/connections-strategies/connections-strategies.service';
@@ -104,6 +108,7 @@ export class KeapConnectionService implements ICrmConnectionService {
provider_slug: 'keap',
vertical: 'crm',
token_type: 'oauth',
+ account_url: providersConfig['crm']['keap'].urls.apiUrl,
access_token: this.cryptoService.encrypt(data.access_token),
refresh_token: this.cryptoService.encrypt(data.refresh_token),
expiration_timestamp: new Date(
diff --git a/packages/api/src/@core/connections/crm/services/pipedrive/pipedrive.service.ts b/packages/api/src/@core/connections/crm/services/pipedrive/pipedrive.service.ts
index cf50636dc..e8eb337ec 100644
--- a/packages/api/src/@core/connections/crm/services/pipedrive/pipedrive.service.ts
+++ b/packages/api/src/@core/connections/crm/services/pipedrive/pipedrive.service.ts
@@ -12,7 +12,11 @@ import { v4 as uuidv4 } from 'uuid';
import { EnvironmentService } from '@@core/environment/environment.service';
import { EncryptionService } from '@@core/encryption/encryption.service';
import { ServiceRegistry } from '../registry.service';
-import { OAuth2AuthData, providerToType } from '@panora/shared';
+import {
+ OAuth2AuthData,
+ providersConfig,
+ providerToType,
+} from '@panora/shared';
import { AuthStrategy } from '@panora/shared';
import { ConnectionsStrategiesService } from '@@core/connections-strategies/connections-strategies.service';
@@ -104,6 +108,7 @@ export class PipedriveConnectionService implements ICrmConnectionService {
provider_slug: 'pipedrive',
vertical: 'crm',
token_type: 'oauth',
+ account_url: providersConfig['crm']['pipedrive'].urls.apiUrl,
access_token: this.cryptoService.encrypt(data.access_token),
refresh_token: this.cryptoService.encrypt(data.refresh_token),
expiration_timestamp: new Date(
diff --git a/packages/api/src/@core/connections/crm/services/teamleader/teamleader.service.ts b/packages/api/src/@core/connections/crm/services/teamleader/teamleader.service.ts
index 74c5f20f7..48f09a133 100644
--- a/packages/api/src/@core/connections/crm/services/teamleader/teamleader.service.ts
+++ b/packages/api/src/@core/connections/crm/services/teamleader/teamleader.service.ts
@@ -12,7 +12,11 @@ import {
ICrmConnectionService,
} from '../../types';
import { ServiceRegistry } from '../registry.service';
-import { OAuth2AuthData, providerToType } from '@panora/shared';
+import {
+ OAuth2AuthData,
+ providersConfig,
+ providerToType,
+} from '@panora/shared';
import { AuthStrategy } from '@panora/shared';
import { ConnectionsStrategiesService } from '@@core/connections-strategies/connections-strategies.service';
@@ -90,7 +94,7 @@ export class TeamleaderConnectionService implements ICrmConnectionService {
data: {
access_token: this.cryptoService.encrypt(data.access_token),
refresh_token: this.cryptoService.encrypt(data.refresh_token),
- account_url: '',
+ account_url: providersConfig['crm']['teamleader'].urls.apiUrl,
expiration_timestamp: new Date(
new Date().getTime() + Number(data.expires_in) * 1000,
),
diff --git a/packages/api/src/@core/connections/crm/services/teamwork/teamwork.service.ts b/packages/api/src/@core/connections/crm/services/teamwork/teamwork.service.ts
index ad099bf44..efab60ab2 100644
--- a/packages/api/src/@core/connections/crm/services/teamwork/teamwork.service.ts
+++ b/packages/api/src/@core/connections/crm/services/teamwork/teamwork.service.ts
@@ -12,7 +12,11 @@ import {
ICrmConnectionService,
} from '../../types';
import { ServiceRegistry } from '../registry.service';
-import { OAuth2AuthData, providerToType } from '@panora/shared';
+import {
+ OAuth2AuthData,
+ providersConfig,
+ providerToType,
+} from '@panora/shared';
import { AuthStrategy } from '@panora/shared';
import { ConnectionsStrategiesService } from '@@core/connections-strategies/connections-strategies.service';
@@ -77,6 +81,9 @@ export class TeamworkConnectionService implements ICrmConnectionService {
let db_res;
const connection_token = uuidv4();
+ //get the right BASE URL API
+ const BASE_API_URL =
+ CREDENTIALS.SUBDOMAIN + providersConfig['crm']['teamwork'].urls.apiUrl;
if (isNotUnique) {
db_res = await this.prisma.connections.update({
@@ -97,6 +104,7 @@ export class TeamworkConnectionService implements ICrmConnectionService {
provider_slug: 'teamwork',
vertical: 'crm',
token_type: 'oauth',
+ account_url: BASE_API_URL,
access_token: this.cryptoService.encrypt(data.access_token),
status: 'valid',
created_at: new Date(),
diff --git a/packages/api/src/@core/connections/crm/services/zendesk/zendesk.service.ts b/packages/api/src/@core/connections/crm/services/zendesk/zendesk.service.ts
index 378884e87..a57205c19 100644
--- a/packages/api/src/@core/connections/crm/services/zendesk/zendesk.service.ts
+++ b/packages/api/src/@core/connections/crm/services/zendesk/zendesk.service.ts
@@ -12,7 +12,11 @@ import { v4 as uuidv4 } from 'uuid';
import { EnvironmentService } from '@@core/environment/environment.service';
import { EncryptionService } from '@@core/encryption/encryption.service';
import { ServiceRegistry } from '../registry.service';
-import { OAuth2AuthData, providerToType } from '@panora/shared';
+import {
+ OAuth2AuthData,
+ providersConfig,
+ providerToType,
+} from '@panora/shared';
import { AuthStrategy } from '@panora/shared';
import { ConnectionsStrategiesService } from '@@core/connections-strategies/connections-strategies.service';
@@ -108,6 +112,7 @@ export class ZendeskConnectionService implements ICrmConnectionService {
provider_slug: 'zendesk',
vertical: 'crm',
token_type: 'oauth',
+ account_url: providersConfig['crm']['zendesk'].urls.apiUrl,
access_token: this.cryptoService.encrypt(data.access_token),
refresh_token: data.refresh_token
? this.cryptoService.encrypt(data.refresh_token)
diff --git a/packages/api/src/@core/connections/crm/services/zoho/zoho.service.ts b/packages/api/src/@core/connections/crm/services/zoho/zoho.service.ts
index c40508032..57eb20088 100644
--- a/packages/api/src/@core/connections/crm/services/zoho/zoho.service.ts
+++ b/packages/api/src/@core/connections/crm/services/zoho/zoho.service.ts
@@ -12,16 +12,41 @@ import { v4 as uuidv4 } from 'uuid';
import { EnvironmentService } from '@@core/environment/environment.service';
import { EncryptionService } from '@@core/encryption/encryption.service';
import { ServiceRegistry } from '../registry.service';
-import { OAuth2AuthData, providerToType } from '@panora/shared';
+import {
+ OAuth2AuthData,
+ providersConfig,
+ providerToType,
+} from '@panora/shared';
import { AuthStrategy } from '@panora/shared';
import { ConnectionsStrategiesService } from '@@core/connections-strategies/connections-strategies.service';
-const ZOHOLocations = {
- us: 'https://accounts.zoho.com',
- eu: 'https://accounts.zoho.eu',
- in: 'https://accounts.zoho.in',
- au: 'https://accounts.zoho.com.au',
- jp: 'https://accounts.zoho.jp',
+type ZohoUrlType = {
+ [key: string]: {
+ authBase: string;
+ apiBase: string;
+ };
+};
+export const ZOHOLocations: ZohoUrlType = {
+ us: {
+ authBase: 'https://accounts.zoho.com',
+ apiBase: 'https://www.zohoapis.com',
+ },
+ eu: {
+ authBase: 'https://accounts.zoho.eu',
+ apiBase: 'https://www.zohoapis.eu',
+ },
+ in: {
+ authBase: 'https://accounts.zoho.in',
+ apiBase: 'https://www.zohoapis.in',
+ },
+ au: {
+ authBase: 'https://accounts.zoho.com.au',
+ apiBase: 'https://www.zohoapis.com.au',
+ },
+ jp: {
+ authBase: 'https://accounts.zoho.jp',
+ apiBase: 'https://www.zohoapis.jp',
+ },
};
export interface ZohoOAuthResponse {
@@ -32,6 +57,7 @@ export interface ZohoOAuthResponse {
expires_in: number;
}
+//TODO: manage domains
@Injectable()
export class ZohoConnectionService implements ICrmConnectionService {
private readonly type: string;
@@ -77,9 +103,9 @@ export class ZohoConnectionService implements ICrmConnectionService {
code: code,
});
//no refresh token
- const domain = ZOHOLocations[location];
+ const authDomain = ZOHOLocations[location].authBase;
const res = await axios.post(
- `${domain}/oauth/v2/token`,
+ `${authDomain}/oauth/v2/token`,
formData.toString(),
{
headers: {
@@ -91,6 +117,7 @@ export class ZohoConnectionService implements ICrmConnectionService {
this.logger.log('OAuth credentials : zoho ' + JSON.stringify(data));
let db_res;
const connection_token = uuidv4();
+ const apiDomain = ZOHOLocations[location].apiBase;
if (isNotUnique) {
db_res = await this.prisma.connections.update({
@@ -107,7 +134,7 @@ export class ZohoConnectionService implements ICrmConnectionService {
),
status: 'valid',
created_at: new Date(),
- account_url: domain,
+ account_url: apiDomain + providersConfig['crm']['zoho'].urls.apiUrl,
},
});
} else {
@@ -133,7 +160,7 @@ export class ZohoConnectionService implements ICrmConnectionService {
linked_users: {
connect: { id_linked_user: linkedUserId },
},
- account_url: domain,
+ account_url: apiDomain + providersConfig['crm']['zoho'].urls.apiUrl,
},
});
}
diff --git a/packages/api/src/@core/connections/ticketing/services/aha/aha.service.ts b/packages/api/src/@core/connections/ticketing/services/aha/aha.service.ts
index 71af88eeb..3a0f241c8 100644
--- a/packages/api/src/@core/connections/ticketing/services/aha/aha.service.ts
+++ b/packages/api/src/@core/connections/ticketing/services/aha/aha.service.ts
@@ -12,7 +12,7 @@ import {
ITicketingConnectionService,
} from '../../types';
import { ServiceRegistry } from '../registry.service';
-import { AuthStrategy } from '@panora/shared';
+import { AuthStrategy, providersConfig } from '@panora/shared';
import { OAuth2AuthData, providerToType } from '@panora/shared';
import { ConnectionsStrategiesService } from '@@core/connections-strategies/connections-strategies.service';
@@ -65,7 +65,7 @@ export class AhaConnectionService implements ITicketingConnectionService {
grant_type: 'authorization_code',
});
const res = await axios.post(
- `${CREDENTIALS.SUBDOMAIN!}/oauth/token`,
+ `${CREDENTIALS.SUBDOMAIN}/oauth/token`,
formData.toString(),
{
headers: {
@@ -80,6 +80,9 @@ export class AhaConnectionService implements ITicketingConnectionService {
let db_res;
const connection_token = uuidv4();
+ //get the right BASE URL API
+ const BASE_API_URL =
+ CREDENTIALS.SUBDOMAIN + providersConfig['ticketing']['aha'].urls.apiUrl;
if (isNotUnique) {
db_res = await this.prisma.connections.update({
@@ -88,7 +91,7 @@ export class AhaConnectionService implements ITicketingConnectionService {
},
data: {
access_token: this.cryptoService.encrypt(data.access_token),
- account_url: CREDENTIALS.SUBDOMAIN!,
+ account_url: BASE_API_URL,
status: 'valid',
created_at: new Date(),
},
@@ -101,7 +104,7 @@ export class AhaConnectionService implements ITicketingConnectionService {
provider_slug: 'aha',
vertical: 'ticketing',
token_type: 'oauth',
- account_url: CREDENTIALS.SUBDOMAIN!,
+ account_url: BASE_API_URL,
access_token: this.cryptoService.encrypt(data.access_token),
status: 'valid',
created_at: new Date(),
diff --git a/packages/api/src/@core/connections/ticketing/services/asana/asana.service.ts b/packages/api/src/@core/connections/ticketing/services/asana/asana.service.ts
new file mode 100644
index 000000000..5d72478a2
--- /dev/null
+++ b/packages/api/src/@core/connections/ticketing/services/asana/asana.service.ts
@@ -0,0 +1,179 @@
+import { Injectable } from '@nestjs/common';
+import axios from 'axios';
+import { PrismaService } from '@@core/prisma/prisma.service';
+import { Action, handleServiceError } from '@@core/utils/errors';
+import { LoggerService } from '@@core/logger/logger.service';
+import { v4 as uuidv4 } from 'uuid';
+import { EnvironmentService } from '@@core/environment/environment.service';
+import { EncryptionService } from '@@core/encryption/encryption.service';
+import {
+ CallbackParams,
+ RefreshParams,
+ ITicketingConnectionService,
+} from '../../types';
+import { ServiceRegistry } from '../registry.service';
+import { AuthStrategy, providersConfig } from '@panora/shared';
+import { OAuth2AuthData, providerToType } from '@panora/shared';
+import { ConnectionsStrategiesService } from '@@core/connections-strategies/connections-strategies.service';
+
+export type AsanaOAuthResponse = {
+ access_token: string;
+ refresh_token: string;
+ expires_in: number;
+ token_type: string;
+ data: {
+ id: number;
+ gid: string;
+ name: string;
+ email: string;
+ };
+};
+
+@Injectable()
+export class AsanaConnectionService implements ITicketingConnectionService {
+ private readonly type: string;
+
+ constructor(
+ private prisma: PrismaService,
+ private logger: LoggerService,
+ private env: EnvironmentService,
+ private cryptoService: EncryptionService,
+ private registry: ServiceRegistry,
+ private cService: ConnectionsStrategiesService,
+ ) {
+ this.logger.setContext(AsanaConnectionService.name);
+ this.registry.registerService('asana', this);
+ this.type = providerToType('asana', 'ticketing', AuthStrategy.oauth2);
+ }
+
+ async handleCallback(opts: CallbackParams) {
+ try {
+ const { linkedUserId, projectId, code } = opts;
+ const isNotUnique = await this.prisma.connections.findFirst({
+ where: {
+ id_linked_user: linkedUserId,
+ provider_slug: 'asana',
+ vertical: 'ticketing',
+ },
+ });
+
+ //reconstruct the redirect URI that was passed in the githubend it must be the same
+ const REDIRECT_URI = `${this.env.getOAuthRredirectBaseUrl()}/connections/oauth/callback`;
+ const CREDENTIALS = (await this.cService.getCredentials(
+ projectId,
+ this.type,
+ )) as OAuth2AuthData;
+
+ const formData = new URLSearchParams({
+ client_id: CREDENTIALS.CLIENT_ID,
+ client_secret: CREDENTIALS.CLIENT_SECRET,
+ redirect_uri: REDIRECT_URI,
+ code: code,
+ grant_type: 'authorization_code',
+ });
+ const res = await axios.post(
+ 'https://app.asana.com/-/oauth_token',
+ formData.toString(),
+ {
+ headers: {
+ 'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
+ },
+ },
+ );
+ const data: AsanaOAuthResponse = res.data;
+ this.logger.log(
+ 'OAuth credentials : asana ticketing ' + JSON.stringify(data),
+ );
+
+ let db_res;
+ const connection_token = uuidv4();
+
+ if (isNotUnique) {
+ db_res = await this.prisma.connections.update({
+ where: {
+ id_connection: isNotUnique.id_connection,
+ },
+ data: {
+ access_token: this.cryptoService.encrypt(data.access_token),
+ refresh_token: this.cryptoService.encrypt(data.refresh_token),
+ account_url: providersConfig['ticketing']['asana'].urls.apiUrl,
+ expiration_timestamp: new Date(
+ new Date().getTime() + Number(data.expires_in) * 1000,
+ ),
+ status: 'valid',
+ created_at: new Date(),
+ },
+ });
+ } else {
+ db_res = await this.prisma.connections.create({
+ data: {
+ id_connection: uuidv4(),
+ connection_token: connection_token,
+ provider_slug: 'asana',
+ vertical: 'ticketing',
+ token_type: 'oauth',
+ account_url: providersConfig['ticketing']['asana'].urls.apiUrl,
+ access_token: this.cryptoService.encrypt(data.access_token),
+ refresh_token: this.cryptoService.encrypt(data.refresh_token),
+ expiration_timestamp: new Date(
+ new Date().getTime() + Number(data.expires_in) * 1000,
+ ),
+ status: 'valid',
+ created_at: new Date(),
+ projects: {
+ connect: { id_project: projectId },
+ },
+ linked_users: {
+ connect: { id_linked_user: linkedUserId },
+ },
+ },
+ });
+ }
+ return db_res;
+ } catch (error) {
+ handleServiceError(error, this.logger, 'asana', Action.oauthCallback);
+ }
+ }
+
+ async handleTokenRefresh(opts: RefreshParams) {
+ try {
+ const { connectionId, refreshToken, projectId } = opts;
+ const CREDENTIALS = (await this.cService.getCredentials(
+ projectId,
+ this.type,
+ )) as OAuth2AuthData;
+ const formData = new URLSearchParams({
+ client_id: CREDENTIALS.CLIENT_ID,
+ client_secret: CREDENTIALS.CLIENT_SECRET,
+ grant_type: 'refresh_token',
+ refresh_token: this.cryptoService.decrypt(refreshToken),
+ });
+ const res = await axios.post(
+ 'https://app.asana.com/-/oauth_token',
+ formData.toString(),
+ {
+ headers: {
+ 'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
+ Authorization: `Basic Q1JFREVOVElBTFMuQ0xJRU5UX0lEfTokewogICAgICAgICAgICAgICAgICBDUkVERU5USUFMUy5DTElFTlRfU0VDUkVUCiAgICAgICAgICAgICAgfQ==`,
+ },
+ },
+ );
+ const data: AsanaOAuthResponse = res.data;
+ await this.prisma.connections.update({
+ where: {
+ id_connection: connectionId,
+ },
+ data: {
+ access_token: this.cryptoService.encrypt(data.access_token),
+ refresh_token: this.cryptoService.encrypt(data.refresh_token),
+ expiration_timestamp: new Date(
+ new Date().getTime() + Number(data.expires_in) * 1000,
+ ),
+ },
+ });
+ this.logger.log('OAuth credentials updated : asana ');
+ } catch (error) {
+ handleServiceError(error, this.logger, 'asana', Action.oauthRefresh);
+ }
+ }
+}
diff --git a/packages/api/src/@core/connections/ticketing/services/clickup/clickup.service.ts b/packages/api/src/@core/connections/ticketing/services/clickup/clickup.service.ts
index 83248f2c0..b36c8df34 100644
--- a/packages/api/src/@core/connections/ticketing/services/clickup/clickup.service.ts
+++ b/packages/api/src/@core/connections/ticketing/services/clickup/clickup.service.ts
@@ -12,7 +12,11 @@ import {
ITicketingConnectionService,
} from '../../types';
import { ServiceRegistry } from '../registry.service';
-import { OAuth2AuthData, providerToType } from '@panora/shared';
+import {
+ OAuth2AuthData,
+ providersConfig,
+ providerToType,
+} from '@panora/shared';
import { AuthStrategy } from '@panora/shared';
import { ConnectionsStrategiesService } from '@@core/connections-strategies/connections-strategies.service';
@@ -98,6 +102,7 @@ export class ClickupConnectionService implements ITicketingConnectionService {
provider_slug: 'clickup',
vertical: 'ticketing',
token_type: 'oauth',
+ account_url: providersConfig['ticketing']['clickup'].urls.apiUrl,
access_token: this.cryptoService.encrypt(data.access_token),
refresh_token: '',
expiration_timestamp: '',
diff --git a/packages/api/src/@core/connections/ticketing/services/front/front.service.ts b/packages/api/src/@core/connections/ticketing/services/front/front.service.ts
index 9f0aed530..e1fb6381a 100644
--- a/packages/api/src/@core/connections/ticketing/services/front/front.service.ts
+++ b/packages/api/src/@core/connections/ticketing/services/front/front.service.ts
@@ -12,7 +12,7 @@ import {
ITicketingConnectionService,
} from '../../types';
import { ServiceRegistry } from '../registry.service';
-import { AuthStrategy } from '@panora/shared';
+import { AuthStrategy, providersConfig } from '@panora/shared';
import { OAuth2AuthData, providerToType } from '@panora/shared';
import { ConnectionsStrategiesService } from '@@core/connections-strategies/connections-strategies.service';
@@ -106,6 +106,7 @@ export class FrontConnectionService implements ITicketingConnectionService {
provider_slug: 'front',
vertical: 'ticketing',
token_type: 'oauth',
+ account_url: providersConfig['ticketing']['front'].urls.apiUrl,
access_token: this.cryptoService.encrypt(data.access_token),
refresh_token: this.cryptoService.encrypt(data.refresh_token),
expiration_timestamp: new Date(
diff --git a/packages/api/src/@core/connections/ticketing/services/github/github.service.ts b/packages/api/src/@core/connections/ticketing/services/github/github.service.ts
index 918392e77..b668b1116 100644
--- a/packages/api/src/@core/connections/ticketing/services/github/github.service.ts
+++ b/packages/api/src/@core/connections/ticketing/services/github/github.service.ts
@@ -12,7 +12,11 @@ import {
ITicketingConnectionService,
} from '../../types';
import { ServiceRegistry } from '../registry.service';
-import { OAuth2AuthData, providerToType } from '@panora/shared';
+import {
+ OAuth2AuthData,
+ providersConfig,
+ providerToType,
+} from '@panora/shared';
import { AuthStrategy } from '@panora/shared';
import { ConnectionsStrategiesService } from '@@core/connections-strategies/connections-strategies.service';
@@ -106,6 +110,7 @@ export class GithubConnectionService implements ITicketingConnectionService {
connection_token: connection_token,
provider_slug: 'github',
vertical: 'ticketing',
+ account_url: providersConfig['ticketing']['github'].urls.apiUrl,
token_type: 'oauth',
access_token: this.cryptoService.encrypt(data.access_token),
refresh_token: this.cryptoService.encrypt(data.refresh_token),
diff --git a/packages/api/src/@core/connections/ticketing/services/gitlab/gitlab.service.ts b/packages/api/src/@core/connections/ticketing/services/gitlab/gitlab.service.ts
index d9794346f..f00ea7ab4 100644
--- a/packages/api/src/@core/connections/ticketing/services/gitlab/gitlab.service.ts
+++ b/packages/api/src/@core/connections/ticketing/services/gitlab/gitlab.service.ts
@@ -12,7 +12,7 @@ import {
ITicketingConnectionService,
} from '../../types';
import { ServiceRegistry } from '../registry.service';
-import { AuthStrategy } from '@panora/shared';
+import { AuthStrategy, providersConfig } from '@panora/shared';
import { OAuth2AuthData, providerToType } from '@panora/shared';
import { ConnectionsStrategiesService } from '@@core/connections-strategies/connections-strategies.service';
@@ -82,6 +82,8 @@ export class GitlabConnectionService implements ITicketingConnectionService {
let db_res;
const connection_token = uuidv4();
+ const BASE_API_URL =
+ CREDENTIALS.SUBDOMAIN + providersConfig['ticketing']['gitlab'].urls.apiUrl;
if (isNotUnique) {
db_res = await this.prisma.connections.update({
@@ -106,6 +108,7 @@ export class GitlabConnectionService implements ITicketingConnectionService {
provider_slug: 'gitlab',
vertical: 'ticketing',
token_type: 'oauth',
+ account_url: BASE_API_URL,
access_token: this.cryptoService.encrypt(data.access_token),
refresh_token: this.cryptoService.encrypt(data.refresh_token),
expiration_timestamp: new Date(
diff --git a/packages/api/src/@core/connections/ticketing/services/gorgias/gorgias.service.ts b/packages/api/src/@core/connections/ticketing/services/gorgias/gorgias.service.ts
index f9f1eeadc..1d8d5bb8f 100644
--- a/packages/api/src/@core/connections/ticketing/services/gorgias/gorgias.service.ts
+++ b/packages/api/src/@core/connections/ticketing/services/gorgias/gorgias.service.ts
@@ -12,7 +12,11 @@ import {
ITicketingConnectionService,
} from '../../types';
import { ServiceRegistry } from '../registry.service';
-import { OAuth2AuthData, providerToType } from '@panora/shared';
+import {
+ OAuth2AuthData,
+ providersConfig,
+ providerToType,
+} from '@panora/shared';
import { AuthStrategy } from '@panora/shared';
import { ConnectionsStrategiesService } from '@@core/connections-strategies/connections-strategies.service';
@@ -68,8 +72,9 @@ export class GorgiasConnectionService implements ITicketingConnectionService {
code: code,
grant_type: 'authorization_code',
});
+
const res = await axios.post(
- `${CREDENTIALS.SUBDOMAIN!}/oauth/token`,
+ `${CREDENTIALS.SUBDOMAIN}/oauth/token`,
formData.toString(),
{
headers: {
@@ -85,6 +90,10 @@ export class GorgiasConnectionService implements ITicketingConnectionService {
let db_res;
const connection_token = uuidv4();
+ //get the right BASE URL API
+ const BASE_API_URL =
+ CREDENTIALS.SUBDOMAIN + providersConfig['ticketing']['gorgias'].urls.apiUrl;
+
if (isNotUnique) {
db_res = await this.prisma.connections.update({
where: {
@@ -93,7 +102,7 @@ export class GorgiasConnectionService implements ITicketingConnectionService {
data: {
access_token: this.cryptoService.encrypt(data.access_token),
refresh_token: this.cryptoService.encrypt(data.refresh_token),
- account_url: CREDENTIALS.SUBDOMAIN!,
+ account_url: BASE_API_URL,
expiration_timestamp: new Date(
new Date().getTime() + Number(data.expires_in) * 1000,
),
@@ -109,7 +118,7 @@ export class GorgiasConnectionService implements ITicketingConnectionService {
provider_slug: 'gorgias',
vertical: 'ticketing',
token_type: 'oauth',
- account_url: CREDENTIALS.SUBDOMAIN!,
+ account_url: BASE_API_URL,
access_token: this.cryptoService.encrypt(data.access_token),
refresh_token: this.cryptoService.encrypt(data.refresh_token),
expiration_timestamp: new Date(
@@ -145,7 +154,7 @@ export class GorgiasConnectionService implements ITicketingConnectionService {
)) as OAuth2AuthData;
const res = await axios.post(
- `${CREDENTIALS.SUBDOMAIN!}/oauth/token`,
+ `${CREDENTIALS.SUBDOMAIN}/oauth/token`,
formData.toString(),
{
headers: {
diff --git a/packages/api/src/@core/connections/ticketing/services/jira/jira.service.ts b/packages/api/src/@core/connections/ticketing/services/jira/jira.service.ts
index 458ef701d..b29e1bcd2 100644
--- a/packages/api/src/@core/connections/ticketing/services/jira/jira.service.ts
+++ b/packages/api/src/@core/connections/ticketing/services/jira/jira.service.ts
@@ -102,7 +102,7 @@ export class JiraConnectionService implements ITicketingConnectionService {
const sites_scopes: JiraCloudIdInformation[] = res_.data;
let cloud_id: string;
for (const site of sites_scopes) {
- if (site.url == 'https://panora.atlassian.net') {
+ if (site.url == CREDENTIALS.SUBDOMAIN) {
cloud_id = site.id;
break;
}
diff --git a/packages/api/src/@core/connections/ticketing/services/jira_service_mgmt/jira.service.ts b/packages/api/src/@core/connections/ticketing/services/jira_service_mgmt/jira.service.ts
index 33820e25c..cba849b77 100644
--- a/packages/api/src/@core/connections/ticketing/services/jira_service_mgmt/jira.service.ts
+++ b/packages/api/src/@core/connections/ticketing/services/jira_service_mgmt/jira.service.ts
@@ -113,7 +113,7 @@ export class JiraServiceMgmtConnectionService
let cloud_id: string;
for (const site of sites_scopes) {
//todo
- if (site.url == 'https://panora.atlassian.net') {
+ if (site.url == CREDENTIALS.SUBDOMAIN) {
cloud_id = site.id;
break;
}
diff --git a/packages/api/src/@core/connections/ticketing/services/linear/linear.service.ts b/packages/api/src/@core/connections/ticketing/services/linear/linear.service.ts
index 2e4338e7c..7ced77587 100644
--- a/packages/api/src/@core/connections/ticketing/services/linear/linear.service.ts
+++ b/packages/api/src/@core/connections/ticketing/services/linear/linear.service.ts
@@ -12,7 +12,7 @@ import {
ITicketingConnectionService,
} from '../../types';
import { ServiceRegistry } from '../registry.service';
-import { AuthStrategy } from '@panora/shared';
+import { AuthStrategy, providersConfig } from '@panora/shared';
import { OAuth2AuthData, providerToType } from '@panora/shared';
import { ConnectionsStrategiesService } from '@@core/connections-strategies/connections-strategies.service';
@@ -105,6 +105,7 @@ export class LinearConnectionService implements ITicketingConnectionService {
provider_slug: 'linear',
vertical: 'ticketing',
token_type: 'oauth',
+ account_url: providersConfig['ticketing']['linear'].urls.apiUrl,
access_token: this.cryptoService.encrypt(data.access_token),
refresh_token: '',
expiration_timestamp: new Date(
diff --git a/packages/api/src/@core/connections/crm/services/affinity/affinity.service.ts b/packages/api/src/@core/connections/ticketing/services/wrike/wrike.service.ts
similarity index 70%
rename from packages/api/src/@core/connections/crm/services/affinity/affinity.service.ts
rename to packages/api/src/@core/connections/ticketing/services/wrike/wrike.service.ts
index 226b8be58..4bc527610 100644
--- a/packages/api/src/@core/connections/crm/services/affinity/affinity.service.ts
+++ b/packages/api/src/@core/connections/ticketing/services/wrike/wrike.service.ts
@@ -9,21 +9,23 @@ import { EncryptionService } from '@@core/encryption/encryption.service';
import {
CallbackParams,
RefreshParams,
- ICrmConnectionService,
+ ITicketingConnectionService,
} from '../../types';
import { ServiceRegistry } from '../registry.service';
+import { AuthStrategy, providersConfig } from '@panora/shared';
import { OAuth2AuthData, providerToType } from '@panora/shared';
-import { AuthStrategy } from '@panora/shared';
import { ConnectionsStrategiesService } from '@@core/connections-strategies/connections-strategies.service';
-export type AffinityOAuthResponse = {
+export type WrikeOAuthResponse = {
access_token: string;
refresh_token: string;
- expires_at: string;
+ expires_in: string;
+ host: string;
+ token_type: string;
};
@Injectable()
-export class AffinityConnectionService implements ICrmConnectionService {
+export class WrikeConnectionService implements ITicketingConnectionService {
private readonly type: string;
constructor(
@@ -34,9 +36,9 @@ export class AffinityConnectionService implements ICrmConnectionService {
private registry: ServiceRegistry,
private cService: ConnectionsStrategiesService,
) {
- this.logger.setContext(AffinityConnectionService.name);
- this.registry.registerService('affinity', this);
- this.type = providerToType('affinity', 'crm', AuthStrategy.oauth2);
+ this.logger.setContext(WrikeConnectionService.name);
+ this.registry.registerService('wrike', this);
+ this.type = providerToType('wrike', 'ticketing', AuthStrategy.oauth2);
}
async handleCallback(opts: CallbackParams) {
@@ -45,8 +47,8 @@ export class AffinityConnectionService implements ICrmConnectionService {
const isNotUnique = await this.prisma.connections.findFirst({
where: {
id_linked_user: linkedUserId,
- provider_slug: `affinity`,
- vertical: 'crm',
+ provider_slug: 'wrike',
+ vertical: 'ticketing',
},
});
@@ -64,15 +66,18 @@ export class AffinityConnectionService implements ICrmConnectionService {
code: code,
grant_type: 'authorization_code',
});
- const subdomain = 'panora';
- const res = await axios.post('', formData.toString(), {
- headers: {
- 'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
+ const res = await axios.post(
+ 'https://login.wrike.com/oauth2/token',
+ formData.toString(),
+ {
+ headers: {
+ 'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
+ },
},
- });
- const data: AffinityOAuthResponse = res.data;
+ );
+ const data: WrikeOAuthResponse = res.data;
this.logger.log(
- 'OAuth credentials : affinity ticketing ' + JSON.stringify(data),
+ 'OAuth credentials : wrike ticketing ' + JSON.stringify(data),
);
let db_res;
@@ -86,9 +91,11 @@ export class AffinityConnectionService implements ICrmConnectionService {
data: {
access_token: this.cryptoService.encrypt(data.access_token),
refresh_token: this.cryptoService.encrypt(data.refresh_token),
- account_url: '',
+ account_url:
+ `https://${data.host}` +
+ providersConfig['ticketing']['wriker'].urls.apiUrl,
expiration_timestamp: new Date(
- new Date().getTime() + Number(data.expires_at) * 1000,
+ new Date().getTime() + Number(data.expires_in) * 1000,
),
status: 'valid',
created_at: new Date(),
@@ -99,14 +106,16 @@ export class AffinityConnectionService implements ICrmConnectionService {
data: {
id_connection: uuidv4(),
connection_token: connection_token,
- provider_slug: 'affinity',
- vertical: 'crm',
+ provider_slug: 'wrike',
+ vertical: 'ticketing',
token_type: 'oauth',
- account_url: '',
+ account_url:
+ `https://${data.host}` +
+ providersConfig['ticketing']['wriker'].urls.apiUrl,
access_token: this.cryptoService.encrypt(data.access_token),
refresh_token: this.cryptoService.encrypt(data.refresh_token),
expiration_timestamp: new Date(
- new Date().getTime() + Number(data.expires_at) * 1000,
+ new Date().getTime() + Number(data.expires_in) * 1000,
),
status: 'valid',
created_at: new Date(),
@@ -121,30 +130,29 @@ export class AffinityConnectionService implements ICrmConnectionService {
}
return db_res;
} catch (error) {
- handleServiceError(error, this.logger, 'affinity', Action.oauthCallback);
+ handleServiceError(error, this.logger, 'wrike', Action.oauthCallback);
}
}
async handleTokenRefresh(opts: RefreshParams) {
try {
const { connectionId, refreshToken, projectId } = opts;
- const formData = new URLSearchParams({
- grant_type: 'refresh_token',
- refresh_token: this.cryptoService.decrypt(refreshToken),
- });
const CREDENTIALS = (await this.cService.getCredentials(
projectId,
this.type,
)) as OAuth2AuthData;
-
- //const subdomain = 'panora';
+ const formData = new URLSearchParams({
+ client_id: CREDENTIALS.CLIENT_ID,
+ client_secret: CREDENTIALS.CLIENT_SECRET,
+ grant_type: 'refresh_token',
+ refresh_token: this.cryptoService.decrypt(refreshToken),
+ });
const res = await axios.post('', formData.toString(), {
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
- Authorization: `Basic JHt0aGlzLmVudi5nZXRgQWZmaW5pdHlTZWNyZXRgKCkuQ0xJRU5UX0lEfTokewogICAgICAgICAgICAgICAgdGhpcy5lbnYuZ2V0YEFmZmluaXR5U2VjcmV0YCgpLkNMSUVOVF9TRUNSRVQKICAgICAgICAgICAgICB9`,
},
});
- const data: AffinityOAuthResponse = res.data;
+ const data: WrikeOAuthResponse = res.data;
await this.prisma.connections.update({
where: {
id_connection: connectionId,
@@ -153,13 +161,13 @@ export class AffinityConnectionService implements ICrmConnectionService {
access_token: this.cryptoService.encrypt(data.access_token),
refresh_token: this.cryptoService.encrypt(data.refresh_token),
expiration_timestamp: new Date(
- new Date().getTime() + Number(data.expires_at) * 1000,
+ new Date().getTime() + Number(data.expires_in) * 1000,
),
},
});
- this.logger.log('OAuth credentials updated : affinity ');
+ this.logger.log('OAuth credentials updated : wrike ');
} catch (error) {
- handleServiceError(error, this.logger, 'affinity', Action.oauthRefresh);
+ handleServiceError(error, this.logger, 'wrike', Action.oauthRefresh);
}
}
}
diff --git a/packages/api/src/@core/connections/ticketing/services/zendesk/zendesk.service.ts b/packages/api/src/@core/connections/ticketing/services/zendesk/zendesk.service.ts
index 8a095dfee..d77c6abde 100644
--- a/packages/api/src/@core/connections/ticketing/services/zendesk/zendesk.service.ts
+++ b/packages/api/src/@core/connections/ticketing/services/zendesk/zendesk.service.ts
@@ -12,7 +12,7 @@ import {
ITicketingConnectionService,
} from '../../types';
import { ServiceRegistry } from '../registry.service';
-import { AuthStrategy } from '@panora/shared';
+import { AuthStrategy, providersConfig } from '@panora/shared';
import { OAuth2AuthData, providerToType } from '@panora/shared';
import { ConnectionsStrategiesService } from '@@core/connections-strategies/connections-strategies.service';
@@ -67,7 +67,7 @@ export class ZendeskConnectionService implements ITicketingConnectionService {
//const subdomain = 'panora7548';
const res = await axios.post(
- `${CREDENTIALS.SUBDOMAIN!}/oauth/tokens`,
+ `${CREDENTIALS.SUBDOMAIN}/oauth/tokens`,
formData.toString(),
{
headers: {
@@ -82,6 +82,9 @@ export class ZendeskConnectionService implements ITicketingConnectionService {
let db_res;
const connection_token = uuidv4();
+ //get the right BASE URL API
+ const BASE_API_URL =
+ CREDENTIALS.SUBDOMAIN + providersConfig['ticketing']['zendesk'].urls.apiUrl;
if (isNotUnique) {
db_res = await this.prisma.connections.update({
@@ -90,7 +93,7 @@ export class ZendeskConnectionService implements ITicketingConnectionService {
},
data: {
access_token: this.cryptoService.encrypt(data.access_token),
- account_url: CREDENTIALS.SUBDOMAIN!,
+ account_url: BASE_API_URL,
refresh_token: '',
expiration_timestamp: new Date(), //TODO
status: 'valid',
@@ -105,7 +108,7 @@ export class ZendeskConnectionService implements ITicketingConnectionService {
provider_slug: 'zendesk',
vertical: 'ticketing',
token_type: 'oauth',
- account_url: CREDENTIALS.SUBDOMAIN!,
+ account_url: BASE_API_URL,
access_token: this.cryptoService.encrypt(data.access_token),
refresh_token: '',
expiration_timestamp: new Date(), //TODO
diff --git a/packages/api/src/@core/connections/ticketing/ticketing.connection.module.ts b/packages/api/src/@core/connections/ticketing/ticketing.connection.module.ts
index 70cb5822b..d5b6bdee0 100644
--- a/packages/api/src/@core/connections/ticketing/ticketing.connection.module.ts
+++ b/packages/api/src/@core/connections/ticketing/ticketing.connection.module.ts
@@ -17,6 +17,9 @@ import { GitlabConnectionService } from './services/gitlab/gitlab.service';
import { ClickupConnectionService } from './services/clickup/clickup.service';
import { GorgiasConnectionService } from './services/gorgias/gorgias.service';
import { ConnectionsStrategiesService } from '@@core/connections-strategies/connections-strategies.service';
+import { AhaConnectionService } from './services/aha/aha.service';
+import { AsanaConnectionService } from './services/asana/asana.service';
+import { WrikeConnectionService } from './services/wrike/wrike.service';
@Module({
imports: [WebhookModule],
@@ -39,6 +42,9 @@ import { ConnectionsStrategiesService } from '@@core/connections-strategies/conn
GitlabConnectionService,
ClickupConnectionService,
GorgiasConnectionService,
+ AhaConnectionService,
+ AsanaConnectionService,
+ WrikeConnectionService,
],
exports: [TicketingConnectionsService],
})
diff --git a/packages/api/src/@core/field-mapping/field-mapping.service.ts b/packages/api/src/@core/field-mapping/field-mapping.service.ts
index d31f403d7..0d4bc02b6 100644
--- a/packages/api/src/@core/field-mapping/field-mapping.service.ts
+++ b/packages/api/src/@core/field-mapping/field-mapping.service.ts
@@ -130,8 +130,11 @@ export class FieldMappingService {
},
});
const provider = providersConfig[vertical][providerId.toLowerCase()];
+ //TODO: handle case where apiUrl is == "" or starts with "/"
+ if (!provider.urls.apiUrl || !provider.urls.customPropertiesUrl)
+ throw new Error('proivder urls are invalid');
const resp = await axios.get(
- provider.apiUrl + provider.customPropertiesUrl,
+ provider.urls.apiUrl + provider.urls.customPropertiesUrl,
{
headers: {
'Content-Type': 'application/json',
diff --git a/packages/api/src/@core/passthrough/passthrough.service.ts b/packages/api/src/@core/passthrough/passthrough.service.ts
index 5f5e9c81a..44b2e88bf 100644
--- a/packages/api/src/@core/passthrough/passthrough.service.ts
+++ b/packages/api/src/@core/passthrough/passthrough.service.ts
@@ -42,7 +42,8 @@ export class PassthroughService {
},
});
const intId = integrationId.toLowerCase();
- const providerUrl = providersConfig[vertical.toLowerCase()][intId].apiUrl;
+ const providerUrl = providersConfig[vertical.toLowerCase()][intId].urls.apiUrl;
+ //TODO: handle case where apiUrl is == "" or starts with "/"
const BASE_URL = `${providerUrl}${path}`;
const connection = await this.prisma.connections.findFirst({
where: {
diff --git a/packages/api/src/crm/company/services/hubspot/index.ts b/packages/api/src/crm/company/services/hubspot/index.ts
index ce8ebb3c7..7514dc756 100644
--- a/packages/api/src/crm/company/services/hubspot/index.ts
+++ b/packages/api/src/crm/company/services/hubspot/index.ts
@@ -43,7 +43,7 @@ export class HubspotService implements ICompanyService {
properties: companyData,
};
const resp = await axios.post(
- `https://api.hubapi.com/crm/v3/objects/companies`,
+ `${connection.account_url}/objects/companies`,
JSON.stringify(dataBody),
{
headers: {
@@ -85,7 +85,7 @@ export class HubspotService implements ICompanyService {
const commonPropertyNames = Object.keys(commonCompanyHubspotProperties);
const allProperties = [...commonPropertyNames, ...custom_properties];
- const baseURL = 'https://api.hubapi.com/crm/v3/objects/companies';
+ const baseURL = '${connection.account_url}/objects/companies';
const queryString = allProperties
.map((prop) => `properties=${encodeURIComponent(prop)}`)
diff --git a/packages/api/src/crm/company/services/pipedrive/index.ts b/packages/api/src/crm/company/services/pipedrive/index.ts
index 3f4f65987..a012edc01 100644
--- a/packages/api/src/crm/company/services/pipedrive/index.ts
+++ b/packages/api/src/crm/company/services/pipedrive/index.ts
@@ -37,7 +37,7 @@ export class PipedriveService implements ICompanyService {
},
});
const resp = await axios.post(
- `https://api.pipedrive.com/v1/organizations`,
+ `${connection.account_url}/organizations`,
JSON.stringify(companyData),
{
headers: {
@@ -76,17 +76,14 @@ export class PipedriveService implements ICompanyService {
vertical: 'crm',
},
});
- const resp = await axios.get(
- `https://api.pipedrive.com/v1/organizations`,
- {
- headers: {
- 'Content-Type': 'application/json',
- Authorization: `Bearer ${this.cryptoService.decrypt(
- connection.access_token,
- )}`,
- },
+ const resp = await axios.get(`${connection.account_url}/organizations`, {
+ headers: {
+ 'Content-Type': 'application/json',
+ Authorization: `Bearer ${this.cryptoService.decrypt(
+ connection.access_token,
+ )}`,
},
- );
+ });
return {
data: resp.data.data,
diff --git a/packages/api/src/crm/company/services/zendesk/index.ts b/packages/api/src/crm/company/services/zendesk/index.ts
index 7f93e2a43..fa597c351 100644
--- a/packages/api/src/crm/company/services/zendesk/index.ts
+++ b/packages/api/src/crm/company/services/zendesk/index.ts
@@ -36,7 +36,7 @@ export class ZendeskService implements ICompanyService {
},
});
const resp = await axios.post(
- `https://api.getbase.com/v2/contacts`,
+ `${connection.account_url}/contacts`,
{
data: companyData,
},
@@ -78,7 +78,7 @@ export class ZendeskService implements ICompanyService {
vertical: 'crm',
},
});
- const resp = await axios.get(`https://api.getbase.com/v2/contacts`, {
+ const resp = await axios.get(`${connection.account_url}/contacts`, {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.cryptoService.decrypt(
diff --git a/packages/api/src/crm/company/services/zoho/index.ts b/packages/api/src/crm/company/services/zoho/index.ts
index 52e61eec2..f9e4f9016 100644
--- a/packages/api/src/crm/company/services/zoho/index.ts
+++ b/packages/api/src/crm/company/services/zoho/index.ts
@@ -37,7 +37,7 @@ export class ZohoService implements ICompanyService {
},
});
const resp = await axios.post(
- `https://www.zohoapis.eu/crm/v3/Companys`,
+ `${connection.account_url}/Companys`,
{ data: [companyData] },
{
headers: {
@@ -80,7 +80,7 @@ export class ZohoService implements ICompanyService {
//TODO: handle fields
const fields = 'First_Name,Last_Name,Full_Name,Email,Phone';
const resp = await axios.get(
- `https://www.zohoapis.eu/crm/v3/Companys?fields=${fields}`,
+ `${connection.account_url}/Companys?fields=${fields}`,
{
headers: {
'Content-Type': 'application/json',
diff --git a/packages/api/src/crm/contact/services/attio/index.ts b/packages/api/src/crm/contact/services/attio/index.ts
index b843ac210..0e2145a08 100644
--- a/packages/api/src/crm/contact/services/attio/index.ts
+++ b/packages/api/src/crm/contact/services/attio/index.ts
@@ -9,6 +9,7 @@ import { EncryptionService } from '@@core/encryption/encryption.service';
import { ApiResponse } from '@@core/utils/types';
import { ServiceRegistry } from '../registry.service';
import { AttioContactInput, AttioContactOutput } from './types';
+import { providersConfig } from '@panora/shared';
@Injectable()
export class AttioService implements IContactService {
@@ -36,9 +37,8 @@ export class AttioService implements IContactService {
vertical: 'crm',
},
});
-
const resp = await axios.post(
- `https://api.attio.com/v2/objects/people/records`,
+ `${connection.account_url}/objects/people/records`,
JSON.stringify({
data: contactData,
}),
diff --git a/packages/api/src/crm/contact/services/hubspot/index.ts b/packages/api/src/crm/contact/services/hubspot/index.ts
index 37da950d7..a7b39e873 100644
--- a/packages/api/src/crm/contact/services/hubspot/index.ts
+++ b/packages/api/src/crm/contact/services/hubspot/index.ts
@@ -44,7 +44,7 @@ export class HubspotService implements IContactService {
properties: contactData,
};
const resp = await axios.post(
- `https://api.hubapi.com/crm/v3/objects/contacts/`,
+ `${connection.account_url}/objects/contacts`,
JSON.stringify(dataBody),
{
headers: {
@@ -86,13 +86,12 @@ export class HubspotService implements IContactService {
const commonPropertyNames = Object.keys(commonHubspotProperties);
const allProperties = [...commonPropertyNames, ...custom_properties];
- const baseURL = 'https://api.hubapi.com/crm/v3/objects/contacts/';
const queryString = allProperties
.map((prop) => `properties=${encodeURIComponent(prop)}`)
.join('&');
- const url = `${baseURL}?${queryString}`;
+ const url = `${connection.account_url}/?${queryString}`;
const resp = await axios.get(url, {
headers: {
diff --git a/packages/api/src/crm/contact/services/pipedrive/index.ts b/packages/api/src/crm/contact/services/pipedrive/index.ts
index 2f7d763b2..7b5350a16 100644
--- a/packages/api/src/crm/contact/services/pipedrive/index.ts
+++ b/packages/api/src/crm/contact/services/pipedrive/index.ts
@@ -38,7 +38,7 @@ export class PipedriveService implements IContactService {
});
const resp = await axios.post(
- `https://api.pipedrive.com/v1/persons`,
+ `${connection.account_url}/persons`,
JSON.stringify(contactData),
{
headers: {
@@ -77,7 +77,7 @@ export class PipedriveService implements IContactService {
vertical: 'crm',
},
});
- const resp = await axios.get(`https://api.pipedrive.com/v1/persons`, {
+ const resp = await axios.get(`${connection.account_url}/persons`, {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.cryptoService.decrypt(
diff --git a/packages/api/src/crm/contact/services/zendesk/index.ts b/packages/api/src/crm/contact/services/zendesk/index.ts
index b6bace3d0..4d96e4396 100644
--- a/packages/api/src/crm/contact/services/zendesk/index.ts
+++ b/packages/api/src/crm/contact/services/zendesk/index.ts
@@ -36,7 +36,7 @@ export class ZendeskService implements IContactService {
},
});
const resp = await axios.post(
- `https://api.getbase.com/v2/contacts`,
+ `${connection.account_url}/contacts`,
{
data: contactData,
},
@@ -78,7 +78,7 @@ export class ZendeskService implements IContactService {
vertical: 'crm',
},
});
- const resp = await axios.get(`https://api.getbase.com/v2/contacts`, {
+ const resp = await axios.get(`${connection.account_url}/contacts`, {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.cryptoService.decrypt(
diff --git a/packages/api/src/crm/contact/services/zoho/index.ts b/packages/api/src/crm/contact/services/zoho/index.ts
index 6396fa87b..2b5ddc9c3 100644
--- a/packages/api/src/crm/contact/services/zoho/index.ts
+++ b/packages/api/src/crm/contact/services/zoho/index.ts
@@ -36,8 +36,9 @@ export class ZohoService implements IContactService {
vertical: 'crm',
},
});
+ //todo
const resp = await axios.post(
- `https://www.zohoapis.eu/crm/v3/Contacts`,
+ `${connection.account_url}/Contacts`,
{ data: [contactData] },
{
headers: {
@@ -80,7 +81,7 @@ export class ZohoService implements IContactService {
//TODO: handle fields
const fields = 'First_Name,Last_Name,Full_Name,Email,Phone';
const resp = await axios.get(
- `https://www.zohoapis.eu/crm/v3/Contacts?fields=${fields}`,
+ `${connection.account_url}/Contacts?fields=${fields}`,
{
headers: {
'Content-Type': 'application/json',
diff --git a/packages/api/src/crm/deal/services/hubspot/index.ts b/packages/api/src/crm/deal/services/hubspot/index.ts
index 72452cce9..37ac7f2e7 100644
--- a/packages/api/src/crm/deal/services/hubspot/index.ts
+++ b/packages/api/src/crm/deal/services/hubspot/index.ts
@@ -42,7 +42,7 @@ export class HubspotService implements IDealService {
properties: dealData,
};
const resp = await axios.post(
- `https://api.hubapi.com/crm/v3/objects/deals`,
+ `${connection.account_url}/objects/deals`,
JSON.stringify(dataBody),
{
headers: {
@@ -85,7 +85,7 @@ export class HubspotService implements IDealService {
const commonPropertyNames = Object.keys(commonDealHubspotProperties);
const allProperties = [...commonPropertyNames, ...custom_properties];
- const baseURL = 'https://api.hubapi.com/crm/v3/objects/deals';
+ const baseURL = '${connection.account_url}/objects/deals';
const queryString = allProperties
.map((prop) => `properties=${encodeURIComponent(prop)}`)
diff --git a/packages/api/src/crm/deal/services/zendesk/index.ts b/packages/api/src/crm/deal/services/zendesk/index.ts
index 06b388cd2..f8a994afe 100644
--- a/packages/api/src/crm/deal/services/zendesk/index.ts
+++ b/packages/api/src/crm/deal/services/zendesk/index.ts
@@ -36,7 +36,7 @@ export class ZendeskService implements IDealService {
},
});
const resp = await axios.post(
- `https://api.getbase.com/v2/deals`,
+ `${connection.account_url}/deals`,
{
data: dealData,
},
@@ -78,7 +78,7 @@ export class ZendeskService implements IDealService {
vertical: 'crm',
},
});
- const resp = await axios.get(`https://api.getbase.com/v2/deals`, {
+ const resp = await axios.get(`${connection.account_url}/deals`, {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.cryptoService.decrypt(
diff --git a/packages/api/src/crm/deal/services/zoho/index.ts b/packages/api/src/crm/deal/services/zoho/index.ts
index a7e004a94..391cc61db 100644
--- a/packages/api/src/crm/deal/services/zoho/index.ts
+++ b/packages/api/src/crm/deal/services/zoho/index.ts
@@ -36,7 +36,7 @@ export class ZohoService implements IDealService {
},
});
const resp = await axios.post(
- `https://www.zohoapis.eu/crm/v3/Deals`,
+ `${connection.account_url}/Deals`,
{ data: [dealData] },
{
headers: {
@@ -79,7 +79,7 @@ export class ZohoService implements IDealService {
//TODO: handle fields
const fields = 'First_Name,Last_Name,Full_Name,Email,Phone';
const resp = await axios.get(
- `https://www.zohoapis.eu/crm/v3/Deals?fields=${fields}`,
+ `${connection.account_url}/Deals?fields=${fields}`,
{
headers: {
'Content-Type': 'application/json',
diff --git a/packages/api/src/crm/engagement/services/hubspot/index.ts b/packages/api/src/crm/engagement/services/hubspot/index.ts
index bad92c754..70664fadf 100644
--- a/packages/api/src/crm/engagement/services/hubspot/index.ts
+++ b/packages/api/src/crm/engagement/services/hubspot/index.ts
@@ -86,7 +86,7 @@ export class HubspotService implements IEngagementService {
properties: engagementData,
};
const resp = await axios.post(
- `https://api.hubapi.com/crm/v3/objects/calls`,
+ `${connection.account_url}/objects/calls`,
JSON.stringify(dataBody),
{
headers: {
@@ -129,7 +129,7 @@ export class HubspotService implements IEngagementService {
properties: engagementData,
};
const resp = await axios.post(
- `https://api.hubapi.com/crm/v3/objects/calls`,
+ `${connection.account_url}/objects/calls`,
JSON.stringify(dataBody),
{
headers: {
@@ -172,7 +172,7 @@ export class HubspotService implements IEngagementService {
properties: engagementData,
};
const resp = await axios.post(
- `https://api.hubapi.com/crm/v3/objects/emails`,
+ `${connection.account_url}/objects/emails`,
JSON.stringify(dataBody),
{
headers: {
@@ -238,7 +238,7 @@ export class HubspotService implements IEngagementService {
const commonPropertyNames = Object.keys(commonCallHubspotProperties);
const allProperties = [...commonPropertyNames, ...custom_properties];
- const baseURL = 'https://api.hubapi.com/crm/v3/objects/calls';
+ const baseURL = '${connection.account_url}/objects/calls';
const queryString = allProperties
.map((prop) => `properties=${encodeURIComponent(prop)}`)
@@ -287,7 +287,7 @@ export class HubspotService implements IEngagementService {
const commonPropertyNames = Object.keys(commonMeetingHubspotProperties);
const allProperties = [...commonPropertyNames, ...custom_properties];
- const baseURL = 'https://api.hubapi.com/crm/v3/objects/meetings';
+ const baseURL = '${connection.account_url}/objects/meetings';
const queryString = allProperties
.map((prop) => `properties=${encodeURIComponent(prop)}`)
@@ -333,7 +333,7 @@ export class HubspotService implements IEngagementService {
const commonPropertyNames = Object.keys(commonCallHubspotProperties);
const allProperties = [...commonPropertyNames, ...custom_properties];
- const baseURL = 'https://api.hubapi.com/crm/v3/objects/emails';
+ const baseURL = '${connection.account_url}/objects/emails';
const queryString = allProperties
.map((prop) => `properties=${encodeURIComponent(prop)}`)
diff --git a/packages/api/src/crm/engagement/services/pipedrive/index.ts b/packages/api/src/crm/engagement/services/pipedrive/index.ts
index f3b4562dd..4369b2cc0 100644
--- a/packages/api/src/crm/engagement/services/pipedrive/index.ts
+++ b/packages/api/src/crm/engagement/services/pipedrive/index.ts
@@ -90,7 +90,7 @@ export class PipedriveService implements IEngagementService {
},
});
- const resp = await axios.get(`https://api.pipedrive.com/v1/activities`, {
+ const resp = await axios.get(`${connection.account_url}/activities`, {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.cryptoService.decrypt(
@@ -129,7 +129,7 @@ export class PipedriveService implements IEngagementService {
},
});
- const resp = await axios.get(`https://api.pipedrive.com/v1/activities`, {
+ const resp = await axios.get(`${connection.account_url}/activities`, {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.cryptoService.decrypt(
@@ -168,7 +168,7 @@ export class PipedriveService implements IEngagementService {
},
});
- const resp = await axios.get(`https://api.pipedrive.com/v1/activities`, {
+ const resp = await axios.get(`${connection.account_url}/activities`, {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.cryptoService.decrypt(
diff --git a/packages/api/src/crm/engagement/services/zendesk/index.ts b/packages/api/src/crm/engagement/services/zendesk/index.ts
index 4162fcef3..a1caf1e53 100644
--- a/packages/api/src/crm/engagement/services/zendesk/index.ts
+++ b/packages/api/src/crm/engagement/services/zendesk/index.ts
@@ -63,7 +63,7 @@ export class ZendeskService implements IEngagementService {
},
});
const resp = await axios.post(
- `https://api.getbase.com/v2/engagements`,
+ `${connection.account_url}/engagements`,
{
data: engagementData,
},
@@ -129,7 +129,7 @@ export class ZendeskService implements IEngagementService {
},
});
- const resp = await axios.get(`https://api.getbase.com/v2/calls`, {
+ const resp = await axios.get(`${connection.account_url}/calls`, {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.cryptoService.decrypt(
diff --git a/packages/api/src/crm/engagement/services/zoho/index.ts b/packages/api/src/crm/engagement/services/zoho/index.ts
index 86c321c1b..62d851f7d 100644
--- a/packages/api/src/crm/engagement/services/zoho/index.ts
+++ b/packages/api/src/crm/engagement/services/zoho/index.ts
@@ -37,7 +37,7 @@ export class ZohoService implements IEngagementService {
},
});
const resp = await axios.post(
- `https://www.zohoapis.eu/crm/v3/Engagements`,
+ `${connection.account_url}/Engagements`,
{ data: [engagementData] },
{
headers: {
@@ -80,7 +80,7 @@ export class ZohoService implements IEngagementService {
//TODO: handle fields
const fields = 'First_Name,Last_Name,Full_Name,Email,Phone';
const resp = await axios.get(
- `https://www.zohoapis.eu/crm/v3/Engagements?fields=${fields}`,
+ `${connection.account_url}/Engagements?fields=${fields}`,
{
headers: {
'Content-Type': 'application/json',
diff --git a/packages/api/src/crm/note/services/hubspot/index.ts b/packages/api/src/crm/note/services/hubspot/index.ts
index 5b34c885e..82d8a4193 100644
--- a/packages/api/src/crm/note/services/hubspot/index.ts
+++ b/packages/api/src/crm/note/services/hubspot/index.ts
@@ -43,7 +43,7 @@ export class HubspotService implements INoteService {
properties: noteData,
};
const resp = await axios.post(
- `https://api.hubapi.com/crm/v3/objects/notes`,
+ `${connection.account_url}/objects/notes`,
JSON.stringify(dataBody),
{
headers: {
@@ -85,7 +85,7 @@ export class HubspotService implements INoteService {
const commonPropertyNames = Object.keys(commonNoteHubspotProperties);
const allProperties = [...commonPropertyNames, ...custom_properties];
- const baseURL = 'https://api.hubapi.com/crm/v3/objects/notes';
+ const baseURL = '${connection.account_url}/objects/notes';
const queryString = allProperties
.map((prop) => `properties=${encodeURIComponent(prop)}`)
diff --git a/packages/api/src/crm/note/services/pipedrive/index.ts b/packages/api/src/crm/note/services/pipedrive/index.ts
index 7aadde72b..c1affafb2 100644
--- a/packages/api/src/crm/note/services/pipedrive/index.ts
+++ b/packages/api/src/crm/note/services/pipedrive/index.ts
@@ -37,7 +37,7 @@ export class PipedriveService implements INoteService {
},
});
const resp = await axios.post(
- `https://api.pipedrive.com/v1/notes`,
+ `${connection.account_url}/notes`,
JSON.stringify(noteData),
{
headers: {
@@ -76,7 +76,7 @@ export class PipedriveService implements INoteService {
vertical: 'crm',
},
});
- const resp = await axios.get(`https://api.pipedrive.com/v1/notes`, {
+ const resp = await axios.get(`${connection.account_url}notes`, {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.cryptoService.decrypt(
diff --git a/packages/api/src/crm/note/services/zendesk/index.ts b/packages/api/src/crm/note/services/zendesk/index.ts
index 2da196330..bd3408ec1 100644
--- a/packages/api/src/crm/note/services/zendesk/index.ts
+++ b/packages/api/src/crm/note/services/zendesk/index.ts
@@ -36,7 +36,7 @@ export class ZendeskService implements INoteService {
},
});
const resp = await axios.post(
- `https://api.getbase.com/v2/notes`,
+ `${connection.account_url}/notes`,
{
data: noteData,
},
@@ -78,7 +78,7 @@ export class ZendeskService implements INoteService {
vertical: 'crm',
},
});
- const resp = await axios.get(`https://api.getbase.com/v2/notes`, {
+ const resp = await axios.get(`${connection.account_url}/notes`, {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.cryptoService.decrypt(
diff --git a/packages/api/src/crm/note/services/zoho/index.ts b/packages/api/src/crm/note/services/zoho/index.ts
index 02b5a4919..cc84f8d13 100644
--- a/packages/api/src/crm/note/services/zoho/index.ts
+++ b/packages/api/src/crm/note/services/zoho/index.ts
@@ -37,7 +37,7 @@ export class ZohoService implements INoteService {
},
});
const resp = await axios.post(
- `https://www.zohoapis.eu/crm/v3/Notes`,
+ `${connection.account_url}/Notes`,
{ data: [noteData] },
{
headers: {
@@ -80,7 +80,7 @@ export class ZohoService implements INoteService {
//TODO: handle fields
const fields = 'First_Name,Last_Name,Full_Name,Email,Phone';
const resp = await axios.get(
- `https://www.zohoapis.eu/crm/v3/Notes?fields=${fields}`,
+ `${connection.account_url}/Notes?fields=${fields}`,
{
headers: {
'Content-Type': 'application/json',
diff --git a/packages/api/src/crm/stage/services/hubspot/index.ts b/packages/api/src/crm/stage/services/hubspot/index.ts
index a07d9c3b1..046947b7b 100644
--- a/packages/api/src/crm/stage/services/hubspot/index.ts
+++ b/packages/api/src/crm/stage/services/hubspot/index.ts
@@ -44,7 +44,7 @@ export class HubspotService implements IStageService {
const commonPropertyNames = Object.keys(commonStageHubspotProperties);
const allProperties = [...commonPropertyNames, ...custom_properties];
- const baseURL = `https://api.hubapi.com/crm/v3/objects/deals/${res.remote_id}`;
+ const baseURL = `${connection.account_url}/objects/deals/${res.remote_id}`;
const queryString = allProperties
.map((prop) => `properties=${encodeURIComponent(prop)}`)
diff --git a/packages/api/src/crm/stage/services/pipedrive/index.ts b/packages/api/src/crm/stage/services/pipedrive/index.ts
index ab7d6397c..704882971 100644
--- a/packages/api/src/crm/stage/services/pipedrive/index.ts
+++ b/packages/api/src/crm/stage/services/pipedrive/index.ts
@@ -40,7 +40,7 @@ export class PipedriveService implements IStageService {
where: { id_crm_deal: deal_id },
});
- const deals = await axios.get(`https://api.pipedrive.com/v1/deals`, {
+ const deals = await axios.get(`${connection.account_url}/deals`, {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.cryptoService.decrypt(
@@ -52,7 +52,7 @@ export class PipedriveService implements IStageService {
const deal = deals.data.data.find(
(item) => String(item.id) === res.remote_id,
);
- const resp = await axios.get(`https://api.pipedrive.com/v1/stages`, {
+ const resp = await axios.get(`${connection.account_url}/stages`, {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.cryptoService.decrypt(
diff --git a/packages/api/src/crm/stage/services/zendesk/index.ts b/packages/api/src/crm/stage/services/zendesk/index.ts
index 121c5e36a..70db655dc 100644
--- a/packages/api/src/crm/stage/services/zendesk/index.ts
+++ b/packages/api/src/crm/stage/services/zendesk/index.ts
@@ -39,7 +39,7 @@ export class ZendeskService implements IStageService {
where: { id_crm_deal: deal_id },
});
const deal = await axios.get(
- `https://api.getbase.com/v2/deals/${res.remote_id}`,
+ `${connection.account_url}/deals/${res.remote_id}`,
{
headers: {
'Content-Type': 'application/json',
@@ -50,7 +50,7 @@ export class ZendeskService implements IStageService {
},
);
const stage_remote_id: number = deal.data.data.stage_id;
- const resp = await axios.get(`https://api.getbase.com/v2/stages`, {
+ const resp = await axios.get(`${connection.account_url}/stages`, {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.cryptoService.decrypt(
diff --git a/packages/api/src/crm/stage/services/zoho/index.ts b/packages/api/src/crm/stage/services/zoho/index.ts
index fd012aff2..cc38a41ee 100644
--- a/packages/api/src/crm/stage/services/zoho/index.ts
+++ b/packages/api/src/crm/stage/services/zoho/index.ts
@@ -38,7 +38,7 @@ export class ZohoService implements IStageService {
//TODO: handle fields
const fields = 'First_Name,Last_Name,Full_Name,Email,Phone';
const resp = await axios.get(
- `https://www.zohoapis.eu/crm/v3/Stages?fields=${fields}`,
+ `${connection.account_url}/Stages?fields=${fields}`,
{
headers: {
'Content-Type': 'application/json',
diff --git a/packages/api/src/crm/task/services/hubspot/index.ts b/packages/api/src/crm/task/services/hubspot/index.ts
index 26acb1dac..b485e63e6 100644
--- a/packages/api/src/crm/task/services/hubspot/index.ts
+++ b/packages/api/src/crm/task/services/hubspot/index.ts
@@ -43,7 +43,7 @@ export class HubspotService implements ITaskService {
properties: taskData,
};
const resp = await axios.post(
- `https://api.hubapi.com/crm/v3/objects/tasks`,
+ `${connection.account_url}/objects/tasks`,
JSON.stringify(dataBody),
{
headers: {
@@ -85,7 +85,7 @@ export class HubspotService implements ITaskService {
const commonPropertyNames = Object.keys(commonTaskHubspotProperties);
const allProperties = [...commonPropertyNames, ...custom_properties];
- const baseURL = 'https://api.hubapi.com/crm/v3/objects/tasks';
+ const baseURL = '${connection.account_url}/objects/tasks';
const queryString = allProperties
.map((prop) => `properties=${encodeURIComponent(prop)}`)
diff --git a/packages/api/src/crm/task/services/pipedrive/index.ts b/packages/api/src/crm/task/services/pipedrive/index.ts
index 9371370f1..aca95d494 100644
--- a/packages/api/src/crm/task/services/pipedrive/index.ts
+++ b/packages/api/src/crm/task/services/pipedrive/index.ts
@@ -37,7 +37,7 @@ export class PipedriveService implements ITaskService {
},
});
const resp = await axios.post(
- `https://api.pipedrive.com/v1/activities`,
+ `${connection.account_url}/activities`,
JSON.stringify(taskData),
{
headers: {
@@ -77,7 +77,7 @@ export class PipedriveService implements ITaskService {
},
});
const resp = await axios.get(
- `https://api.pipedrive.com/v1/activities?type=task&user_id=${19156166}`,
+ `${connection.account_url}/activities?type=task&user_id=${19156166}`,
{
headers: {
'Content-Type': 'application/json',
diff --git a/packages/api/src/crm/task/services/zendesk/index.ts b/packages/api/src/crm/task/services/zendesk/index.ts
index 3df61d9cd..9cdecad10 100644
--- a/packages/api/src/crm/task/services/zendesk/index.ts
+++ b/packages/api/src/crm/task/services/zendesk/index.ts
@@ -38,7 +38,7 @@ export class ZendeskService implements ITaskService {
});
const resp = await axios.post(
- `https://api.getbase.com/v2/tasks`,
+ `${connection.account_url}/tasks`,
{
data: taskData,
meta: {
@@ -83,7 +83,7 @@ export class ZendeskService implements ITaskService {
vertical: 'crm',
},
});
- const resp = await axios.get(`https://api.getbase.com/v2/tasks`, {
+ const resp = await axios.get(`${connection.account_url}/tasks`, {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.cryptoService.decrypt(
diff --git a/packages/api/src/crm/task/services/zoho/index.ts b/packages/api/src/crm/task/services/zoho/index.ts
index 612a32cd3..dd6b4d0e7 100644
--- a/packages/api/src/crm/task/services/zoho/index.ts
+++ b/packages/api/src/crm/task/services/zoho/index.ts
@@ -37,7 +37,7 @@ export class ZohoService implements ITaskService {
},
});
const resp = await axios.post(
- `https://www.zohoapis.eu/crm/v3/Tasks`,
+ `${connection.account_url}/Tasks`,
{ data: [taskData] },
{
headers: {
@@ -80,7 +80,7 @@ export class ZohoService implements ITaskService {
//TODO: handle fields
const fields = 'First_Name,Last_Name,Full_Name,Email,Phone';
const resp = await axios.get(
- `https://www.zohoapis.eu/crm/v3/Tasks?fields=${fields}`,
+ `${connection.account_url}/Tasks?fields=${fields}`,
{
headers: {
'Content-Type': 'application/json',
diff --git a/packages/api/src/crm/user/services/hubspot/index.ts b/packages/api/src/crm/user/services/hubspot/index.ts
index dc2ab1f0c..4ccddf08e 100644
--- a/packages/api/src/crm/user/services/hubspot/index.ts
+++ b/packages/api/src/crm/user/services/hubspot/index.ts
@@ -39,7 +39,7 @@ export class HubspotService implements IUserService {
const commonPropertyNames = Object.keys(commonUserHubspotProperties);
const allProperties = [...commonPropertyNames, ...custom_properties];
- const baseURL = 'https://api.hubapi.com/crm/v3/owners';
+ const baseURL = '${connection.account_url}/owners';
const queryString = allProperties
.map((prop) => `properties=${encodeURIComponent(prop)}`)
diff --git a/packages/api/src/crm/user/services/pipedrive/index.ts b/packages/api/src/crm/user/services/pipedrive/index.ts
index 77052b6a5..453823167 100644
--- a/packages/api/src/crm/user/services/pipedrive/index.ts
+++ b/packages/api/src/crm/user/services/pipedrive/index.ts
@@ -35,7 +35,7 @@ export class PipedriveService implements IUserService {
vertical: 'crm',
},
});
- const resp = await axios.get(`https://api.pipedrive.com/v1/users`, {
+ const resp = await axios.get(`${connection.account_url}/users`, {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.cryptoService.decrypt(
diff --git a/packages/api/src/crm/user/services/zendesk/index.ts b/packages/api/src/crm/user/services/zendesk/index.ts
index 067702a4d..7fbaf70dc 100644
--- a/packages/api/src/crm/user/services/zendesk/index.ts
+++ b/packages/api/src/crm/user/services/zendesk/index.ts
@@ -34,7 +34,7 @@ export class ZendeskService implements IUserService {
vertical: 'crm',
},
});
- const resp = await axios.get(`https://api.getbase.com/v2/users`, {
+ const resp = await axios.get(`${connection.account_url}/users`, {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.cryptoService.decrypt(
diff --git a/packages/api/src/crm/user/services/zoho/index.ts b/packages/api/src/crm/user/services/zoho/index.ts
index 8238a6eeb..dbea715eb 100644
--- a/packages/api/src/crm/user/services/zoho/index.ts
+++ b/packages/api/src/crm/user/services/zoho/index.ts
@@ -38,7 +38,7 @@ export class ZohoService implements IUserService {
//TODO: handle fields
const fields = 'First_Name,Last_Name,Full_Name,Email,Phone';
const resp = await axios.get(
- `https://www.zohoapis.eu/crm/v3/Users?fields=${fields}`,
+ `${connection.account_url}/Users?fields=${fields}`,
{
headers: {
'Content-Type': 'application/json',
diff --git a/packages/api/src/ticketing/account/services/front/index.ts b/packages/api/src/ticketing/account/services/front/index.ts
index e0d531096..63ae02aa5 100644
--- a/packages/api/src/ticketing/account/services/front/index.ts
+++ b/packages/api/src/ticketing/account/services/front/index.ts
@@ -36,7 +36,7 @@ export class FrontService implements IAccountService {
},
});
- const resp = await axios.get('https://api2.frontapp.com/accounts', {
+ const resp = await axios.get(`${connection.account_url}/accounts`, {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.cryptoService.decrypt(
diff --git a/packages/api/src/ticketing/account/services/zendesk/index.ts b/packages/api/src/ticketing/account/services/zendesk/index.ts
index 714e45cdc..61645fd09 100644
--- a/packages/api/src/ticketing/account/services/zendesk/index.ts
+++ b/packages/api/src/ticketing/account/services/zendesk/index.ts
@@ -40,7 +40,7 @@ export class ZendeskService implements IAccountService {
});
const resp = await axios.get(
- `${connection.account_url}/api/v2/organizations.json`,
+ `${connection.account_url}/organizations.json`,
{
headers: {
'Content-Type': 'application/json',
diff --git a/packages/api/src/ticketing/collection/services/jira/index.ts b/packages/api/src/ticketing/collection/services/jira/index.ts
index 64b101658..2ec6d7046 100644
--- a/packages/api/src/ticketing/collection/services/jira/index.ts
+++ b/packages/api/src/ticketing/collection/services/jira/index.ts
@@ -36,17 +36,14 @@ export class JiraService implements ICollectionService {
},
});
- const resp = await axios.get(
- `${connection.account_url}/rest/api/3/project/search`,
- {
- headers: {
- 'Content-Type': 'application/json',
- Authorization: `Bearer ${this.cryptoService.decrypt(
- connection.access_token,
- )}`,
- },
+ const resp = await axios.get(`${connection.account_url}/project/search`, {
+ headers: {
+ 'Content-Type': 'application/json',
+ Authorization: `Bearer ${this.cryptoService.decrypt(
+ connection.access_token,
+ )}`,
},
- );
+ });
this.logger.log(`Synced jira collections !`);
return {
diff --git a/packages/api/src/ticketing/comment/services/front/index.ts b/packages/api/src/ticketing/comment/services/front/index.ts
index f7e205898..fec2d5608 100644
--- a/packages/api/src/ticketing/comment/services/front/index.ts
+++ b/packages/api/src/ticketing/comment/services/front/index.ts
@@ -86,7 +86,7 @@ export class FrontService implements ICommentService {
// Send request with attachments
resp = await axios.post(
- `https://api2.frontapp.com/conversations/${remoteIdTicket}/comments`,
+ `${connection.account_url}/conversations/${remoteIdTicket}/comments`,
formData,
{
headers: {
@@ -100,7 +100,7 @@ export class FrontService implements ICommentService {
} else {
// Send request without attachments
resp = await axios.post(
- `https://api2.frontapp.com/conversations/${remoteIdTicket}/comments`,
+ `${connection.account_url}/conversations/${remoteIdTicket}/comments`,
JSON.stringify(dataBody),
{
headers: {
@@ -152,7 +152,7 @@ export class FrontService implements ICommentService {
});
const resp = await axios.get(
- `https://api2.frontapp.com/conversations/${ticket.remote_id}/comments`,
+ `${connection.account_url}/conversations/${ticket.remote_id}/comments`,
{
headers: {
'Content-Type': 'application/json',
diff --git a/packages/api/src/ticketing/comment/services/github/index.ts b/packages/api/src/ticketing/comment/services/github/index.ts
index 78aea85ce..12c192c6d 100644
--- a/packages/api/src/ticketing/comment/services/github/index.ts
+++ b/packages/api/src/ticketing/comment/services/github/index.ts
@@ -12,6 +12,7 @@ import { OriginalCommentOutput } from '@@core/utils/types/original/original.tick
import { ServiceRegistry } from '../registry.service';
import { GithubCommentInput, GithubCommentOutput } from './types';
+//TODO;
@Injectable()
export class GithubService implements ICommentService {
constructor(
@@ -42,7 +43,7 @@ export class GithubService implements ICommentService {
comment: commentData,
};
const resp = await axios.post(
- `https://api2.frontapp.com/conversations/${remoteIdTicket}/comments`,
+ `${connection.account_url}/conversations/${remoteIdTicket}/comments`,
JSON.stringify(dataBody),
{
headers: {
@@ -91,7 +92,7 @@ export class GithubService implements ICommentService {
});
const resp = await axios.get(
- `https://api2.frontapp.com/conversations/${ticket.remote_id}/comments`,
+ `${connection.account_url}/conversations/${ticket.remote_id}/comments`,
{
headers: {
'Content-Type': 'application/json',
diff --git a/packages/api/src/ticketing/comment/services/gorgias/index.ts b/packages/api/src/ticketing/comment/services/gorgias/index.ts
index 06c8f4344..6184df8ec 100644
--- a/packages/api/src/ticketing/comment/services/gorgias/index.ts
+++ b/packages/api/src/ticketing/comment/services/gorgias/index.ts
@@ -76,7 +76,7 @@ export class GorgiasService implements ICommentService {
};
const resp = await axios.post(
- `${connection.account_url}/api/tickets/${remoteIdTicket}/messages`,
+ `${connection.account_url}/tickets/${remoteIdTicket}/messages`,
JSON.stringify(data),
{
headers: {
diff --git a/packages/api/src/ticketing/comment/services/hubspot/index.ts b/packages/api/src/ticketing/comment/services/hubspot/index.ts
index f844a1383..6dd37e96b 100644
--- a/packages/api/src/ticketing/comment/services/hubspot/index.ts
+++ b/packages/api/src/ticketing/comment/services/hubspot/index.ts
@@ -41,7 +41,7 @@ export class HubspotService implements ICommentService {
comment: commentData,
};
const resp = await axios.post(
- `https://api2.frontapp.com/conversations/${remoteIdTicket}/comments`,
+ `${connection.account_url}/conversations/${remoteIdTicket}/comments`,
JSON.stringify(dataBody),
{
headers: {
@@ -90,7 +90,7 @@ export class HubspotService implements ICommentService {
});
const resp = await axios.get(
- `https://api2.frontapp.com/conversations/${ticket.remote_id}/comments`,
+ `${connection.account_url}/conversations/${ticket.remote_id}/comments`,
{
headers: {
'Content-Type': 'application/json',
diff --git a/packages/api/src/ticketing/comment/services/jira/index.ts b/packages/api/src/ticketing/comment/services/jira/index.ts
index 4e50d3343..b3478b2e9 100644
--- a/packages/api/src/ticketing/comment/services/jira/index.ts
+++ b/packages/api/src/ticketing/comment/services/jira/index.ts
@@ -45,7 +45,7 @@ export class JiraService implements ICommentService {
// Send request without attachments
const resp = await axios.post(
- `${connection.account_url}/rest/api/3/issue/${remoteIdTicket}/comment`,
+ `${connection.account_url}/issue/${remoteIdTicket}/comment`,
JSON.stringify(commentData),
{
headers: {
@@ -91,7 +91,7 @@ export class JiraService implements ICommentService {
// Send request with attachments
const resp_ = await axios.post(
- `${connection.account_url}/rest/api/3/issue/${remoteIdTicket}/attachments`,
+ `${connection.account_url}/issue/${remoteIdTicket}/attachments`,
formData,
{
headers: {
@@ -143,7 +143,7 @@ export class JiraService implements ICommentService {
},
});
const resp = await axios.get(
- `${connection.account_url}/rest/api/3/issue/${ticket.remote_id}/comment`,
+ `${connection.account_url}/issue/${ticket.remote_id}/comment`,
{
headers: {
'Content-Type': 'application/json',
diff --git a/packages/api/src/ticketing/comment/services/zendesk/index.ts b/packages/api/src/ticketing/comment/services/zendesk/index.ts
index 3fbdeceb9..7ba8769be 100644
--- a/packages/api/src/ticketing/comment/services/zendesk/index.ts
+++ b/packages/api/src/ticketing/comment/services/zendesk/index.ts
@@ -66,7 +66,7 @@ export class ZendeskService implements ICommentService {
//TODO:; fetch the right file from AWS s3
const s3File = '';
- const url = `${connection.account_url}/api/v2/uploads.json?filename=${res.file_name}`;
+ const url = `${connection.account_url}/uploads.json?filename=${res.file_name}`;
const resp = await axios.get(url, {
headers: {
@@ -92,7 +92,7 @@ export class ZendeskService implements ICommentService {
//to add a comment on Zendesk you must update a ticket using the Ticket API
const resp = await axios.put(
- `${connection.account_url}/api/v2/tickets/${remoteIdTicket}.json`,
+ `${connection.account_url}/tickets/${remoteIdTicket}.json`,
JSON.stringify(dataBody),
{
headers: {
@@ -144,7 +144,7 @@ export class ZendeskService implements ICommentService {
});
const resp = await axios.get(
- `${connection.account_url}/api/v2/tickets/${ticket.remote_id}/comments.json`,
+ `${connection.account_url}/tickets/${ticket.remote_id}/comments.json`,
{
headers: {
'Content-Type': 'application/json',
diff --git a/packages/api/src/ticketing/contact/services/front/index.ts b/packages/api/src/ticketing/contact/services/front/index.ts
index 81dd621e7..e3ea2c1ab 100644
--- a/packages/api/src/ticketing/contact/services/front/index.ts
+++ b/packages/api/src/ticketing/contact/services/front/index.ts
@@ -41,7 +41,7 @@ export class FrontService implements IContactService {
});
const resp = await axios.get(
- `https://api2.frontapp.com/accounts/${remote_account_id}/contacts`,
+ `${connection.account_url}/accounts/${remote_account_id}/contacts`,
{
headers: {
'Content-Type': 'application/json',
diff --git a/packages/api/src/ticketing/contact/services/gorgias/index.ts b/packages/api/src/ticketing/contact/services/gorgias/index.ts
index b4e1fdf19..25198681f 100644
--- a/packages/api/src/ticketing/contact/services/gorgias/index.ts
+++ b/packages/api/src/ticketing/contact/services/gorgias/index.ts
@@ -40,7 +40,7 @@ export class GorgiasService implements IContactService {
},
});
- const resp = await axios.get(`${connection.account_url}/api/customers`, {
+ const resp = await axios.get(`${connection.account_url}/customers`, {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.cryptoService.decrypt(
diff --git a/packages/api/src/ticketing/contact/services/zendesk/index.ts b/packages/api/src/ticketing/contact/services/zendesk/index.ts
index cc13fb2db..7af57f9e6 100644
--- a/packages/api/src/ticketing/contact/services/zendesk/index.ts
+++ b/packages/api/src/ticketing/contact/services/zendesk/index.ts
@@ -39,7 +39,7 @@ export class ZendeskService implements IContactService {
},
});
- const resp = await axios.get(`${connection.account_url}/api/v2/users`, {
+ const resp = await axios.get(`${connection.account_url}/users`, {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.cryptoService.decrypt(
diff --git a/packages/api/src/ticketing/tag/services/front/index.ts b/packages/api/src/ticketing/tag/services/front/index.ts
index c077454bf..15b5e4bb9 100644
--- a/packages/api/src/ticketing/tag/services/front/index.ts
+++ b/packages/api/src/ticketing/tag/services/front/index.ts
@@ -46,7 +46,7 @@ export class FrontService implements ITagService {
},
});
- const resp = await axios.get('https://api2.frontapp.com/conversations', {
+ const resp = await axios.get(`${connection.account_url}/conversations`, {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.cryptoService.decrypt(
diff --git a/packages/api/src/ticketing/tag/services/gorgias/index.ts b/packages/api/src/ticketing/tag/services/gorgias/index.ts
index 06abbed27..30155db5f 100644
--- a/packages/api/src/ticketing/tag/services/gorgias/index.ts
+++ b/packages/api/src/ticketing/tag/services/gorgias/index.ts
@@ -46,7 +46,7 @@ export class GorgiasService implements ITagService {
},
});
- const resp = await axios.get(`${connection.account_url}/api/tags`, {
+ const resp = await axios.get(`${connection.account_url}/tags`, {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.cryptoService.decrypt(
diff --git a/packages/api/src/ticketing/tag/services/zendesk/index.ts b/packages/api/src/ticketing/tag/services/zendesk/index.ts
index 4f4782518..b50ad900e 100644
--- a/packages/api/src/ticketing/tag/services/zendesk/index.ts
+++ b/packages/api/src/ticketing/tag/services/zendesk/index.ts
@@ -49,7 +49,7 @@ export class ZendeskService implements ITagService {
});
const resp = await axios.get(
- `${connection.account_url}/api/v2/tickets/${ticket.remote_id}/tags`,
+ `${connection.account_url}/tickets/${ticket.remote_id}/tags`,
{
headers: {
'Content-Type': 'application/json',
diff --git a/packages/api/src/ticketing/team/services/clickup/index.ts b/packages/api/src/ticketing/team/services/clickup/index.ts
index a7dcb45a5..cc65bffbd 100644
--- a/packages/api/src/ticketing/team/services/clickup/index.ts
+++ b/packages/api/src/ticketing/team/services/clickup/index.ts
@@ -36,7 +36,7 @@ export class ClickupService implements ITeamService {
},
});
- const resp = await axios.get('https://api2.frontapp.com/teams', {
+ const resp = await axios.get('${connection.account_url}/teams', {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.cryptoService.decrypt(
diff --git a/packages/api/src/ticketing/team/services/front/index.ts b/packages/api/src/ticketing/team/services/front/index.ts
index c98501f38..d10d0dd72 100644
--- a/packages/api/src/ticketing/team/services/front/index.ts
+++ b/packages/api/src/ticketing/team/services/front/index.ts
@@ -36,7 +36,7 @@ export class FrontService implements ITeamService {
},
});
- const resp = await axios.get('https://api2.frontapp.com/teams', {
+ const resp = await axios.get(`${connection.account_url}/teams`, {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.cryptoService.decrypt(
diff --git a/packages/api/src/ticketing/team/services/gorgias/index.ts b/packages/api/src/ticketing/team/services/gorgias/index.ts
index 1a2d70759..69da4c197 100644
--- a/packages/api/src/ticketing/team/services/gorgias/index.ts
+++ b/packages/api/src/ticketing/team/services/gorgias/index.ts
@@ -36,7 +36,7 @@ export class GorgiasService implements ITeamService {
},
});
- const resp = await axios.get(`${connection.account_url}/api/teams`, {
+ const resp = await axios.get(`${connection.account_url}/teams`, {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.cryptoService.decrypt(
diff --git a/packages/api/src/ticketing/team/services/jira/index.ts b/packages/api/src/ticketing/team/services/jira/index.ts
index b8ede2a3a..0a0fb8a2b 100644
--- a/packages/api/src/ticketing/team/services/jira/index.ts
+++ b/packages/api/src/ticketing/team/services/jira/index.ts
@@ -37,7 +37,7 @@ export class JiraService implements ITeamService {
});
const resp = await axios.get(
- `${connection.account_url}/rest/api/3/user/groups`,
+ `${connection.account_url}/user/groups`,
{
headers: {
'Content-Type': 'application/json',
diff --git a/packages/api/src/ticketing/team/services/zendesk/index.ts b/packages/api/src/ticketing/team/services/zendesk/index.ts
index d5fc1e40c..ed3b7dd56 100644
--- a/packages/api/src/ticketing/team/services/zendesk/index.ts
+++ b/packages/api/src/ticketing/team/services/zendesk/index.ts
@@ -40,7 +40,7 @@ export class ZendeskService implements ITeamService {
});
const resp = await axios.get(
- `${connection.account_url}/api/v2/groups.json`,
+ `${connection.account_url}/groups.json`,
{
headers: {
'Content-Type': 'application/json',
diff --git a/packages/api/src/ticketing/ticket/services/front/index.ts b/packages/api/src/ticketing/ticket/services/front/index.ts
index 6a4b6d6da..32154441e 100644
--- a/packages/api/src/ticketing/ticket/services/front/index.ts
+++ b/packages/api/src/ticketing/ticket/services/front/index.ts
@@ -96,7 +96,7 @@ export class FrontService implements ITicketService {
}
resp = await axios.post(
- `https://api2.frontapp.com/conversations`,
+ `${connection.account_url}/conversations`,
formData,
{
headers: {
@@ -109,7 +109,7 @@ export class FrontService implements ITicketService {
);
} else {
resp = await axios.post(
- `https://api2.frontapp.com/conversations`,
+ `${connection.account_url}/conversations`,
JSON.stringify(restOfTicketData),
{
headers: {
@@ -131,7 +131,7 @@ export class FrontService implements ITicketService {
final = { ...final, custom_fields: custom_fields };
}
const tag_resp = await axios.patch(
- `https://api2.frontapp.com/conversations/${resp.data.id}`,
+ `${connection.account_url}/conversations/${resp.data.id}`,
JSON.stringify(final),
{
headers: {
@@ -173,7 +173,7 @@ export class FrontService implements ITicketService {
},
});
- const resp = await axios.get('https://api2.frontapp.com/conversations', {
+ const resp = await axios.get('${connection.account_url}/conversations', {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.cryptoService.decrypt(
diff --git a/packages/api/src/ticketing/ticket/services/gorgias/index.ts b/packages/api/src/ticketing/ticket/services/gorgias/index.ts
index e1751cc3f..8cb59e4bd 100644
--- a/packages/api/src/ticketing/ticket/services/gorgias/index.ts
+++ b/packages/api/src/ticketing/ticket/services/gorgias/index.ts
@@ -76,7 +76,7 @@ export class GorgiasService implements ITicketService {
);
const resp = await axios.post(
- `${connection.account_url}/api/tickets`,
+ `${connection.account_url}/tickets`,
JSON.stringify({ ...ticketData, messages: modifiedComments }),
{
headers: {
@@ -116,7 +116,7 @@ export class GorgiasService implements ITicketService {
},
});
- const resp = await axios.get(`${connection.account_url}/api/tickets`, {
+ const resp = await axios.get(`${connection.account_url}/tickets`, {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.cryptoService.decrypt(
diff --git a/packages/api/src/ticketing/ticket/services/hubspot/index.ts b/packages/api/src/ticketing/ticket/services/hubspot/index.ts
index 2ce23bc04..ad9071172 100644
--- a/packages/api/src/ticketing/ticket/services/hubspot/index.ts
+++ b/packages/api/src/ticketing/ticket/services/hubspot/index.ts
@@ -41,7 +41,7 @@ export class HubspotService implements ITicketService {
});
const dataBody = { properties: ticketData };
const resp = await axios.post(
- `https://api.hubapi.com/crm/v3/objects/tickets`,
+ `${connection.account_url}/objects/tickets`,
JSON.stringify(dataBody),
{
headers: {
@@ -82,7 +82,7 @@ export class HubspotService implements ITicketService {
const commonPropertyNames = Object.keys(commonHubspotProperties);
const allProperties = [...commonPropertyNames, ...custom_properties];
- const baseURL = 'https://api.hubapi.com/crm/v3/objects/tickets/';
+ const baseURL = '${connection.account_url}/objects/tickets/';
const queryString = allProperties
.map((prop) => `properties=${encodeURIComponent(prop)}`)
diff --git a/packages/api/src/ticketing/ticket/services/jira/index.ts b/packages/api/src/ticketing/ticket/services/jira/index.ts
index e9e55ff5f..93f47309d 100644
--- a/packages/api/src/ticketing/ticket/services/jira/index.ts
+++ b/packages/api/src/ticketing/ticket/services/jira/index.ts
@@ -44,7 +44,7 @@ export class JiraService implements ITicketService {
//Add comment by calling the unified comment function but first insert the ticket base data
const resp = await axios.post(
- `${connection.account_url}/rest/api/3/issue`,
+ `${connection.account_url}/issue`,
JSON.stringify(ticketData),
{
headers: {
@@ -85,7 +85,7 @@ export class JiraService implements ITicketService {
},
});
const resp = await axios.get(
- `${connection.account_url}/rest/api/3/search`,
+ `${connection.account_url}/search`,
{
headers: {
'Content-Type': 'application/json',
diff --git a/packages/api/src/ticketing/ticket/services/zendesk/index.ts b/packages/api/src/ticketing/ticket/services/zendesk/index.ts
index 3124fcd31..9232b7d48 100644
--- a/packages/api/src/ticketing/ticket/services/zendesk/index.ts
+++ b/packages/api/src/ticketing/ticket/services/zendesk/index.ts
@@ -56,7 +56,7 @@ export class ZendeskService implements ITicketService {
//TODO:; fetch the right file from AWS s3
const s3File = '';
- const url = `${connection.account_url}/api/v2/uploads.json?filename=${res.file_name}`;
+ const url = `${connection.account_url}/uploads.json?filename=${res.file_name}`;
const resp = await axios.get(url, {
headers: {
@@ -82,7 +82,7 @@ export class ZendeskService implements ITicketService {
}
const resp = await axios.post(
- `${connection.account_url}/api/v2/tickets.json`,
+ `${connection.account_url}/tickets.json`,
JSON.stringify(dataBody),
{
headers: {
@@ -122,7 +122,7 @@ export class ZendeskService implements ITicketService {
});
const resp = await axios.get(
- `${connection.account_url}/api/v2/tickets.json`,
+ `${connection.account_url}/tickets.json`,
{
headers: {
'Content-Type': 'application/json',
diff --git a/packages/api/src/ticketing/user/services/front/index.ts b/packages/api/src/ticketing/user/services/front/index.ts
index a88185bda..2d22630b4 100644
--- a/packages/api/src/ticketing/user/services/front/index.ts
+++ b/packages/api/src/ticketing/user/services/front/index.ts
@@ -36,7 +36,7 @@ export class FrontService implements IUserService {
},
});
- const resp = await axios.get('https://api2.frontapp.com/teammates', {
+ const resp = await axios.get(`${connection.account_url}/teammates`, {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.cryptoService.decrypt(
diff --git a/packages/api/src/ticketing/user/services/gorgias/index.ts b/packages/api/src/ticketing/user/services/gorgias/index.ts
index a07b78a85..6245ea0ce 100644
--- a/packages/api/src/ticketing/user/services/gorgias/index.ts
+++ b/packages/api/src/ticketing/user/services/gorgias/index.ts
@@ -36,7 +36,7 @@ export class GorgiasService implements IUserService {
},
});
- const resp = await axios.get(`${connection.account_url}/api/users`, {
+ const resp = await axios.get(`${connection.account_url}/users`, {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.cryptoService.decrypt(
diff --git a/packages/api/src/ticketing/user/services/jira/index.ts b/packages/api/src/ticketing/user/services/jira/index.ts
index 7a09d9ef3..5c860fa63 100644
--- a/packages/api/src/ticketing/user/services/jira/index.ts
+++ b/packages/api/src/ticketing/user/services/jira/index.ts
@@ -36,7 +36,7 @@ export class JiraService implements IUserService {
},
});
const resp = await axios.get(
- `${connection.account_url}/rest/api/3/users/search`,
+ `${connection.account_url}/users/search`,
{
headers: {
'Content-Type': 'application/json',
diff --git a/packages/api/src/ticketing/user/services/zendesk/index.ts b/packages/api/src/ticketing/user/services/zendesk/index.ts
index d3b8030e8..277bc7677 100644
--- a/packages/api/src/ticketing/user/services/zendesk/index.ts
+++ b/packages/api/src/ticketing/user/services/zendesk/index.ts
@@ -39,7 +39,7 @@ export class ZendeskService implements IUserService {
},
});
- const resp = await axios.get(`${connection.account_url}/api/v2/users`, {
+ const resp = await axios.get(`${connection.account_url}/users`, {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.cryptoService.decrypt(
diff --git a/packages/api/swagger/swagger-spec.json b/packages/api/swagger/swagger-spec.json
index f46d24485..21b94df30 100644
--- a/packages/api/swagger/swagger-spec.json
+++ b/packages/api/swagger/swagger-spec.json
@@ -324,14 +324,7 @@
],
"responses": {
"200": {
- "description": "",
- "content": {
- "application/json": {
- "schema": {
- "type": "object"
- }
- }
- }
+ "description": ""
}
},
"tags": [
@@ -665,7 +658,7 @@
"content": {
"application/json": {
"schema": {
- "type": "object"
+ "type": "number"
}
}
}
diff --git a/packages/shared/package.json b/packages/shared/package.json
index 233b2b6dc..3f6166d87 100644
--- a/packages/shared/package.json
+++ b/packages/shared/package.json
@@ -50,10 +50,10 @@
"supertest": "^6.3.3",
"ts-jest": "^29.1.0",
"ts-node": "^10.9.1",
- "tsconfig-paths": "^4.2.0",
- "typescript": "^5.1.3",
"tsc-watch": "2.2.1",
- "tslint": "5.16.0"
+ "tsconfig-paths": "^4.2.0",
+ "tslint": "5.16.0",
+ "typescript": "^5.1.3"
},
"jest": {
"moduleFileExtensions": [
diff --git a/packages/shared/src/authUrl.ts b/packages/shared/src/authUrl.ts
index bb6ebed40..b7d6c170f 100644
--- a/packages/shared/src/authUrl.ts
+++ b/packages/shared/src/authUrl.ts
@@ -1,6 +1,15 @@
import { OAuth2AuthData, providerToType } from "./envConfig";
import { AuthStrategy, providersConfig, ProviderConfig } from "./utils";
+const randomString = () => {
+ const charSet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
+ let result = '';
+ for (let i = 0; i < length; i++) {
+ const randomIndex = Math.floor(Math.random() * charSet.length);
+ result += charSet[randomIndex];
+ }
+ return result;
+}
interface AuthParams {
projectId: string;
linkedUserId: string;
@@ -83,7 +92,13 @@ const handleOAuth2Url = async (input: HandleOAuth2Url) => {
const clientId = data.CLIENT_ID;
if (!clientId) throw new Error(`No client id for type ${type}`)
- const { scopes, authBaseUrl: baseUrl } = config;
+ const { scopes, urls: urls } = config;
+ const { authBaseUrl: baseUrl } = urls;
+
+ if(!baseUrl) throw new Error(`No authBaseUrl found for type ${type}`)
+
+ //construct the baseAuthUrl based on the fact that client may use custom subdomain
+ const BASE_URL: string = data.SUBDOMAIN ? data.SUBDOMAIN + baseUrl : baseUrl;
if (!baseUrl) {
throw new Error(`Unsupported provider: ${providerName}`);
@@ -92,8 +107,9 @@ const handleOAuth2Url = async (input: HandleOAuth2Url) => {
// Default URL structure
let params = `client_id=${encodeURIComponent(clientId)}&redirect_uri=${encodedRedirectUrl}&state=${state}`;
+ const providersWithoutScopes = ["pipedrive", "clickup", "aha", "freeagent", "teamwork", "attio", "close", "teamleader"]
// Adding scope for providers that require it, except for 'pipedrive'
- if (providerName !== "pipedrive") {
+ if (!providersWithoutScopes.includes(providerName) ) {
params += `&scope=${encodeURIComponent(scopes)}`;
}
@@ -106,15 +122,15 @@ const handleOAuth2Url = async (input: HandleOAuth2Url) => {
case "jira_service_mgmt":
params = `audience=api.atlassian.com&${params}&prompt=consent`;
break;
- case "gitlab":
- params += "&code_challenge=&code_challenge_method=";
+ case "gorgias":
+ params = `&response_type=code&nonce=${randomString()}`;
break;
default:
// For most providers, response_type=code is common
params += "&response_type=code";
}
- const finalAuthUrl = `${baseUrl}?${params}`;
+ const finalAuthUrl = `${BASE_URL}?${params}`;
console.log("Final Authentication : ", finalAuthUrl);
return finalAuthUrl;
}
diff --git a/packages/shared/src/envConfig.ts b/packages/shared/src/envConfig.ts
index ddfc07d3f..88e0e1e62 100644
--- a/packages/shared/src/envConfig.ts
+++ b/packages/shared/src/envConfig.ts
@@ -92,9 +92,9 @@ export function needsSubdomain(provider: string, vertical: string): boolean {
const providerConfig = providersConfig[vertical][provider];
// Check if authBaseUrl and apiUrl start with a '/'
- const authBaseUrlStartsWithSlash = providerConfig.authBaseUrl.startsWith('/');
- const apiUrlStartsWithSlash = providerConfig.apiUrl!.startsWith('/');
-
- // Return true if both URLs start with a '/', otherwise false
- return authBaseUrlStartsWithSlash && apiUrlStartsWithSlash;
+ const authBaseUrlStartsWithSlash = providerConfig.urls.authBaseUrl!.startsWith('/');
+ const apiUrlStartsWithSlash = providerConfig.urls.apiUrl!.startsWith('/');
+ const apiUrlIsBlank = providerConfig.urls.apiUrl! == "";
+
+ return authBaseUrlStartsWithSlash || apiUrlStartsWithSlash || apiUrlIsBlank;
}
diff --git a/packages/shared/src/utils.ts b/packages/shared/src/utils.ts
index 87f6e0052..bbf69829e 100644
--- a/packages/shared/src/utils.ts
+++ b/packages/shared/src/utils.ts
@@ -4,16 +4,19 @@ export enum AuthStrategy {
basic
}
-// TODO : remove clientId
export type ProviderConfig = {
scopes: string;
- authBaseUrl: string;
logoPath: string;
description: string;
active?: boolean;
- apiUrl: string;
customPropertiesUrl?: string;
authStrategy?: AuthStrategy;
+ urls: {
+ docsUrl: string;
+ apiUrl: string;
+ authBaseUrl?: string; //url used to authorize an application on behalf of the user (only when authStrategy is oauth2)
+ customPropertiesUrl?: string;
+ }
};
type VerticalConfig = {
@@ -22,53 +25,69 @@ type VerticalConfig = {
export type ProvidersConfig = {
[vertical: string]: VerticalConfig;
-};
-
+}
-//If authBaseUrl or apiUrl both start with / it means a subdomain is likely needed
+// If authBaseUrl or apiUrl both start with / it means a subdomain is likely needed
+// If authBaseUrl is blank then it must be manually built in the client given the provider (meaning its not deterministic)
export const providersConfig: ProvidersConfig = {
'crm': {
'hubspot': {
scopes: 'crm.objects.contacts.read crm.objects.contacts.write crm.schemas.deals.read crm.schemas.deals.write crm.objects.deals.read crm.objects.deals.write crm.objects.companies.read crm.objects.companies.write crm.objects.owners.read settings.users.read settings.users.write settings.users.teams.read settings.users.teams.write',
- authBaseUrl: 'https://app-eu1.hubspot.com/oauth/authorize',
+ urls: {
+ docsUrl: "https://developers.hubspot.com/docs/api/crm/understanding-the-crm",
+ authBaseUrl: 'https://app-eu1.hubspot.com/oauth/authorize',
+ apiUrl: 'https://api.hubapi.com/crm/v3',
+ customPropertiesUrl: '/properties/v1/contacts/properties',
+ },
logoPath: "https://assets-global.website-files.com/6421a177cdeeaf3c6791b745/64d61202dd99e63d40d446f6_hubspot%20logo.png",
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
- apiUrl: 'https://api.hubapi.com',
- customPropertiesUrl: '/properties/v1/contacts/properties',
authStrategy: AuthStrategy.oauth2
},
'attio': {
scopes: 'record_permission:read',
- authBaseUrl: 'https://app.attio.com/authorize',
+ urls: {
+ docsUrl: "https://developers.attio.com/reference",
+ authBaseUrl: 'https://app.attio.com/authorize',
+ apiUrl: 'https://api.attio.com/v2',
+ customPropertiesUrl: '/docs/standard-objects-people',
+ },
logoPath: "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSJWZsShi0G6mZ451MngEvQrmJ2JIGH-AF8JyFU-q-n3w&s",
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
- apiUrl: 'https://developers.attio.com',
- customPropertiesUrl: '/docs/standard-objects-people',
authStrategy: AuthStrategy.oauth2
},
'zoho': {
scopes: 'ZohoCRM.modules.ALL',
- authBaseUrl: 'https://accounts.zoho.eu/oauth/v2/auth',
+ urls: {
+ docsUrl: "https://www.zoho.com/crm/developer/docs/api/v5/",
+ authBaseUrl: '/oauth/v2/auth',
+ apiUrl: '/crm/v3',
+ customPropertiesUrl: '/settings/fields?module=Contact',
+ },
logoPath: 'https://assets-global.website-files.com/64f68d43d25e5962af5f82dd/64f68d43d25e5962af5f9812_64ad8bbe47c78358489b29fc_645e3ccf636a8d659f320e25_Group%25252012.png',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
- apiUrl: 'https://www.zohoapis.eu/crm/v3',
- customPropertiesUrl: '/settings/fields?module=Contact',
authStrategy: AuthStrategy.oauth2
},
'pipedrive': {
scopes: 'Pipedrive_Scope',
- authBaseUrl: 'https://oauth.pipedrive.com/oauth/authorize',
+ urls: {
+ docsUrl: "https://developers.pipedrive.com/docs/api/v1",
+ authBaseUrl: 'https://oauth.pipedrive.com/oauth/authorize',
+ apiUrl: 'https://api.pipedrive.com/v1',
+ customPropertiesUrl: '/v1/personFields',
+ },
logoPath: 'https://asset.brandfetch.io/idZG_U1qqs/ideqSFbb2E.jpeg',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
- apiUrl: 'https://api.pipedrive.com',
- customPropertiesUrl: '/v1/personFields',
authStrategy: AuthStrategy.oauth2
},
+ //todo
'freshsales': {
scopes: '',
- authBaseUrl: '',
- apiUrl: '',
+ urls: {
+ docsUrl: "",
+ authBaseUrl: '',
+ apiUrl: '',
+ },
logoPath: 'https://play-lh.googleusercontent.com/Mwgb5c2sVHGHoDlthAYPnMGekEOzsvMR5zotxskrl0erKTW-xpZbuIXn7AEIqvrRHQ',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false,
@@ -76,17 +95,23 @@ export const providersConfig: ProvidersConfig = {
},
'zendesk': {
scopes: 'read write',
- authBaseUrl: 'https://api.getbase.com/oauth2/authorize',
+ urls: {
+ docsUrl: "https://developer.zendesk.com/api-reference/sales-crm/introduction/",
+ authBaseUrl: 'https://api.getbase.com/oauth2/authorize',
+ apiUrl: 'https://api.getbase.com/v2',
+ customPropertiesUrl: '/contact/custom_fields',
+ },
logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRNKVceZGVM7PbARp_2bjdOICUxlpS5B29UYlurvh6Z2Q&s',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
- apiUrl: 'https://api.getbase.com/v2',
- customPropertiesUrl: '/contact/custom_fields',
authStrategy: AuthStrategy.oauth2
},
'accelo': {
scopes: '',
- authBaseUrl: 'https://{deployment}.api.accelo.com/oauth2/v0/authorize',
- apiUrl: '',
+ urls: {
+ docsUrl: "https://api.accelo.com/docs/#introduction",
+ authBaseUrl: '/oauth2/v0/authorize',
+ apiUrl: '/api/v0',
+ },
logoPath: 'https://play-lh.googleusercontent.com/j63K2u8ZXukgPs8QPgyXfyoxuNBl_ST7gLx5DEFeczCTtM9e5JNpDjjBy32qLxFS7p0',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false,
@@ -94,8 +119,10 @@ export const providersConfig: ProvidersConfig = {
},
'active_campaign': {
scopes: '',
- authBaseUrl: '',
- apiUrl: '',
+ urls: {
+ docsUrl: "https://developers.activecampaign.com/reference/overview",
+ apiUrl: '/api/3',
+ },
logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSymrBOaXpQab_5RPRZfiOXU7h9dfsduGZeCaZZw59xJA&s',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false,
@@ -103,8 +130,10 @@ export const providersConfig: ProvidersConfig = {
},
'affinity': {
scopes: '',
- authBaseUrl: '',
- apiUrl: 'https://api.affinity.co',
+ urls: {
+ docsUrl: "https://api-docs.affinity.co/#getting-started",
+ apiUrl: 'https://api.affinity.co',
+ },
logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTMRfcwBA9Jn9z9dJQgY3f_H-bBeUzl-jRHNOm8xrmwtA&s',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false,
@@ -112,8 +141,11 @@ export const providersConfig: ProvidersConfig = {
},
'capsule': {
scopes: '',
- authBaseUrl: 'https://api.capsulecrm.com/oauth/authorise',
- apiUrl: 'https://api.capsulecrm.com/api/v2',
+ urls: {
+ docsUrl: "https://developer.capsulecrm.com/",
+ authBaseUrl: 'https://api.capsulecrm.com/oauth/authorise',
+ apiUrl: 'https://api.capsulecrm.com/api/v2',
+ },
logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSjS3qFlJJbQ802nGEV9w2GEgmnAIgJj6JJxe14cH6Wuw&s',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false,
@@ -121,17 +153,23 @@ export const providersConfig: ProvidersConfig = {
},
'close': {
scopes: '',
- authBaseUrl: 'https://app.close.com/oauth2/authorize',
- apiUrl: 'https://api.close.com/api/v1',
+ urls: {
+ docsUrl: "https://developer.close.com/",
+ authBaseUrl: 'https://app.close.com/oauth2/authorize',
+ apiUrl: 'https://api.close.com/api/v1',
+ },
logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTEH77yPBUkStmoc1ZtgJS4XeBmQiaq_Q1vgF5oerOGbg&s',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false,
- authStrategy: AuthStrategy.api_key
+ authStrategy: AuthStrategy.oauth2
},
'copper': {
scopes: '',
- authBaseUrl: 'https://app.copper.com/oauth/authorize',
- apiUrl: 'https://api.copper.com/developer_api/v1',
+ urls: {
+ docsUrl: "https://developer.copper.com/index.html",
+ authBaseUrl: 'https://app.copper.com/oauth/authorize',
+ apiUrl: 'https://api.copper.com/developer_api/v1',
+ },
logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRVa1YDciibzviRJxGovqH4gNgPxpZUAHEz36Bwnj54uQ&s',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false,
@@ -139,70 +177,94 @@ export const providersConfig: ProvidersConfig = {
},
'insightly': {
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "https://api.insightly.com/v3.1/Help#!/Overview/Introduction",
+ apiUrl: '/v3.1',
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false,
authStrategy: AuthStrategy.api_key,
- apiUrl: ''
},
'keap': {
scopes: '',
- authBaseUrl: 'https://accounts.infusionsoft.com/app/oauth/authorize',
- apiUrl: 'https://api.infusionsoft.com/crm/rest/v2',
+ urls: {
+ docsUrl: "https://developer.infusionsoft.com/docs/restv2/",
+ authBaseUrl: 'https://accounts.infusionsoft.com/app/oauth/authorize',
+ apiUrl: 'https://api.infusionsoft.com/crm/rest/v2',
+ },
logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRPYsWSMe9KVWgCIQ8fw-vBOnfTlZaSS6p_43ZhEIx51A&s',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false,
authStrategy: AuthStrategy.oauth2
},
+ //todo
'microsoft_dynamics_sales': {
scopes: '',
- authBaseUrl: '',
- apiUrl: '',
+ urls: {
+ docsUrl: "",
+ authBaseUrl: '',
+ apiUrl: '',
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
+ //todo
'nutshell': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
- logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRbCONyN9DCKfd4E8pzIdItl5VqPTEErpoEn9vHCgblRg&s',
+ urls: {
+ docsUrl: "",
+ authBaseUrl: '',
+ apiUrl: '',
+ }, logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRbCONyN9DCKfd4E8pzIdItl5VqPTEErpoEn9vHCgblRg&s',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false,
- authStrategy: AuthStrategy.api_key
+ authStrategy: AuthStrategy.basic
},
+ //todo
'pipeliner': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
- logoPath: 'https://play-lh.googleusercontent.com/rK9Qv_w9C8Py_aLZdQQDobNdHWSG8KL4dj3cBBQLcimVu-ctxwujA4VE442lIpZ65AE',
+ urls: {
+ docsUrl: "",
+ apiUrl: '',
+ }, logoPath: 'https://play-lh.googleusercontent.com/rK9Qv_w9C8Py_aLZdQQDobNdHWSG8KL4dj3cBBQLcimVu-ctxwujA4VE442lIpZ65AE',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false,
authStrategy: AuthStrategy.api_key
},
'salesflare': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "https://api.salesflare.com/docs#section/Introduction/Getting-Started",
+ apiUrl: 'https://api.salesflare.com',
+ },
logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTesqSVCSaCDrjedsKbepr14iJPySzUwrh7Fg9MhgKh9w&s',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false,
authStrategy: AuthStrategy.api_key
},
+ //todo
'salesforce': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ authBaseUrl: '',
+ apiUrl: '',
+ },
logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTgL4FJb-GptGfxDDkWbIX2CjIM77t5q-d7eCFY6sGsHA&s',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false,
authStrategy: AuthStrategy.oauth2
},
+ //todo
'sugarcrm': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ authBaseUrl: '',
+ apiUrl: '',
+ },
logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQftNERc1ImBHm8MXXuWdhQiFYwW-dXNcogRL1UV8JyHFQGY2BbsbpwKvERwKRB39RH6zw&usqp=CAU',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false,
@@ -210,8 +272,11 @@ export const providersConfig: ProvidersConfig = {
},
'teamleader': {
scopes: '',
- authBaseUrl: 'https://focus.teamleader.eu/oauth2/authorize',
- apiUrl: 'https://api.focus.teamleader.eu',
+ urls: {
+ docsUrl: "https://developer.teamleader.eu/#/introduction/ap-what?",
+ authBaseUrl: 'https://focus.teamleader.eu/oauth2/authorize',
+ apiUrl: 'https://api.focus.teamleader.eu',
+ },
logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTE99rDOwXdRYGET0oeSCqK2kB02slJxZtTeBC79pb8IQ&s',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false,
@@ -219,26 +284,36 @@ export const providersConfig: ProvidersConfig = {
},
'teamwork': {
scopes: '',
- authBaseUrl: 'https://www.teamwork.com/launchpad/login',
- apiUrl: '',
+ urls: {
+ docsUrl: "https://apidocs.teamwork.com/guides/teamwork/getting-started-with-the-teamwork-com-api",
+ authBaseUrl: 'https://www.teamwork.com/launchpad/login',
+ apiUrl: '', //on purpose blank => everything is contained inside the accountUrl(subdomain)
+ },
logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQr6gYDMNagMEicBb4dhKz4BC1fQs72In45QF7Ls6-moA&s',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false,
authStrategy: AuthStrategy.oauth2
},
+ //todo
'vtiger': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: '',
+ },
logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRcUYrYD8lnaFaDN93vwjHhksKJUG3rqlb1TCFC__oPBw&s',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false,
authStrategy: AuthStrategy.basic
},
+ //todo
'twenty': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ authBaseUrl: '',
+ apiUrl: '',
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
@@ -247,294 +322,408 @@ export const providersConfig: ProvidersConfig = {
'ticketing': {
'front': {
scopes: '',
- authBaseUrl: 'https://app.frontapp.com/oauth/authorize',
+ urls: {
+ docsUrl: "",
+ authBaseUrl: 'https://app.frontapp.com/oauth/authorize',
+ apiUrl: 'https://api2.frontapp.com',
+ },
logoPath: 'https://i.pinimg.com/originals/43/a2/43/43a24316bd773798c7638ad98521eb81.png',
description: "Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users",
- apiUrl: 'https://api2.frontapp.com',
authStrategy: AuthStrategy.oauth2
},
'zendesk': {
scopes: 'read write',
- authBaseUrl: 'https://panora7548.zendesk.com/oauth/authorizations/new',
+ urls: {
+ docsUrl: "",
+ authBaseUrl: '/oauth/authorizations/new',
+ apiUrl: '/api/v2',
+ },
logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRNKVceZGVM7PbARp_2bjdOICUxlpS5B29UYlurvh6Z2Q&s',
description: "Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users",
- apiUrl: '/api/v2',
authStrategy: AuthStrategy.oauth2
},
'gorgias': {
scopes: 'write:all openid email profile offline',
- authBaseUrl: '/oauth/authorize',
+ urls: {
+ docsUrl: "",
+ apiUrl: '/api',
+ authBaseUrl: '/oauth/authorize',
+ },
logoPath: 'https://x5h8w2v3.rocketcdn.me/wp-content/uploads/2020/09/FS-AFFI-00660Gorgias.png',
description: "Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users",
- apiUrl: '/api',
authStrategy: AuthStrategy.oauth2
},
'jira': {
scopes: 'read:jira-work manage:jira-project manage:jira-data-provider manage:jira-webhook write:jira-work manage:jira-configuration read:jira-user offline_access',
- authBaseUrl: 'https://auth.atlassian.com/authorize',
+ urls: {
+ docsUrl: "",
+ apiUrl: '/rest/api/3',
+ authBaseUrl: 'https://auth.atlassian.com/authorize',
+ },
logoPath: 'https://logowik.com/content/uploads/images/jira3124.jpg',
description: "Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users",
- apiUrl: '/rest/api/3',
authStrategy: AuthStrategy.oauth2
},
+ //todo
'jira_service_mgmt': {
- apiUrl: '',
scopes: 'read:servicedesk-request manage:servicedesk-customer read:servicemanagement-insight-objects write:servicedesk-request offline_access',
- authBaseUrl: 'https://auth.atlassian.com/authorize',
+ urls: {
+ docsUrl: "",
+ apiUrl: '',
+ authBaseUrl: 'https://auth.atlassian.com/authorize'
+ },
logoPath: '',
description: "Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users",
active: false,
authStrategy: AuthStrategy.oauth2
},
'linear': {
- apiUrl: '',
scopes: 'read,write',
- authBaseUrl: 'https://linear.app/oauth/authorize',
+ urls: {
+ docsUrl: "",
+ apiUrl: 'https://api.linear.app/graphql',
+ authBaseUrl: 'https://linear.app/oauth/authorize',
+ },
logoPath: '',
description: "Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users",
active: false,
authStrategy: AuthStrategy.oauth2
},
'gitlab': {
- apiUrl: '',
scopes: '',
- authBaseUrl: 'https://gitlab.example.com/oauth/authorize',
+ urls: {
+ docsUrl: "",
+ apiUrl: '/api/v4',
+ authBaseUrl: '/oauth/authorize',
+ },
logoPath: '',
description: "Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users",
active: false,
authStrategy: AuthStrategy.oauth2
},
'clickup': {
- apiUrl: '',
scopes: '',
- authBaseUrl: 'https://app.clickup.com/api',
+ urls: {
+ docsUrl: "",
+ apiUrl: 'https://api.clickup.com/v2',
+ authBaseUrl: 'https://app.clickup.com/api',
+ },
logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRewJj9y5yKzSCf-qGgjmdLagEhxfnlZ7TUsvukbfZaIg&s',
description: "Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users",
active: false,
authStrategy: AuthStrategy.oauth2
},
'github': {
- apiUrl: '',
scopes: '',
- authBaseUrl: 'https://api.github.com',
+ urls: {
+ docsUrl: "",
+ apiUrl: 'https://api.github.com',
+ authBaseUrl: 'https://github.com/login/oauth/authorize',
+ },
logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRqz0aID6B-InxK_03P7tCtqpXNXdawBcro67CyEE0I5g&s',
description: "Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users",
active: false,
authStrategy: AuthStrategy.oauth2
},
'aha': {
- apiUrl: '',
scopes: '',
- authBaseUrl: 'https://.aha.io/oauth/authorize',
+ urls: {
+ docsUrl: "",
+ apiUrl: '/api/v1',
+ authBaseUrl: '/oauth/authorize',
+ },
logoPath: 'https://www.aha.io/aha-logo-2x.png',
description: "Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users",
active: false,
authStrategy: AuthStrategy.oauth2
},
'asana': {
- apiUrl: '',
scopes: '',
- authBaseUrl: 'https://api.github.com',
+ urls: {
+ docsUrl: "",
+ apiUrl: 'https://app.asana.com/api/1.0',
+ authBaseUrl: 'https://app.asana.com/-/oauth_authorize',
+ },
logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRqz0aID6B-InxK_03P7tCtqpXNXdawBcro67CyEE0I5g&s',
description: "Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users",
- active: false
+ active: false,
+ authStrategy: AuthStrategy.oauth2
},
+ //todo
'azure': {
- apiUrl: '',
scopes: '',
- authBaseUrl: 'https://api.github.com',
+ urls: {
+ docsUrl: "",
+ apiUrl: '',
+ authBaseUrl: '',
+ },
logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRqz0aID6B-InxK_03P7tCtqpXNXdawBcro67CyEE0I5g&s',
description: "Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users",
active: false
},
+ //todo
'basecamp': {
- apiUrl: '',
scopes: '',
- authBaseUrl: 'https://api.github.com',
- logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRqz0aID6B-InxK_03P7tCtqpXNXdawBcro67CyEE0I5g&s',
+ urls: {
+ docsUrl: "",
+ apiUrl: '',
+ authBaseUrl: '',
+ }, logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRqz0aID6B-InxK_03P7tCtqpXNXdawBcro67CyEE0I5g&s',
description: "Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users",
active: false
},
+ //todo
'bitbucket': {
- apiUrl: '',
scopes: '',
- authBaseUrl: 'https://api.github.com',
- logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRqz0aID6B-InxK_03P7tCtqpXNXdawBcro67CyEE0I5g&s',
+ urls: {
+ docsUrl: "",
+ apiUrl: '',
+ authBaseUrl: '',
+ }, logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRqz0aID6B-InxK_03P7tCtqpXNXdawBcro67CyEE0I5g&s',
description: "Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users",
active: false
},
'dixa': {
- apiUrl: '',
scopes: '',
- authBaseUrl: 'https://api.github.com',
+ urls: {
+ docsUrl: "",
+ apiUrl: 'https://dev.dixa.io',
+ },
logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRqz0aID6B-InxK_03P7tCtqpXNXdawBcro67CyEE0I5g&s',
description: "Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users",
- active: false
+ active: false,
+ authStrategy: AuthStrategy.api_key
},
+ //todo
'freshdesk': {
- apiUrl: '',
scopes: '',
- authBaseUrl: 'https://api.github.com',
+ urls: {
+ docsUrl: "",
+ apiUrl: '',
+ authBaseUrl: '',
+ },
logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRqz0aID6B-InxK_03P7tCtqpXNXdawBcro67CyEE0I5g&s',
description: "Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users",
active: false
},
+ //todo
'freshservice': {
- apiUrl: '',
scopes: '',
- authBaseUrl: 'https://api.github.com',
+ urls: {
+ docsUrl: "",
+ apiUrl: '',
+ authBaseUrl: '',
+ },
logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRqz0aID6B-InxK_03P7tCtqpXNXdawBcro67CyEE0I5g&s',
description: "Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users",
active: false
},
'gladly': {
- apiUrl: '',
scopes: '',
- authBaseUrl: 'https://api.github.com',
+ urls: {
+ docsUrl: "",
+ apiUrl: '/api/v1',
+ },
logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRqz0aID6B-InxK_03P7tCtqpXNXdawBcro67CyEE0I5g&s',
description: "Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users",
- active: false
+ active: false,
+ authStrategy: AuthStrategy.basic
},
+ //todo
'height': {
- apiUrl: '',
scopes: '',
- authBaseUrl: 'https://api.github.com',
+ urls: {
+ docsUrl: "",
+ apiUrl: '',
+ authBaseUrl: '',
+ },
logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRqz0aID6B-InxK_03P7tCtqpXNXdawBcro67CyEE0I5g&s',
description: "Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users",
active: false
},
'help_scout': {
- apiUrl: '',
scopes: '',
- authBaseUrl: 'https://api.github.com',
+ urls: {
+ docsUrl: "",
+ apiUrl: 'https://docsapi.helpscout.net/v1',
+ },
logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRqz0aID6B-InxK_03P7tCtqpXNXdawBcro67CyEE0I5g&s',
description: "Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users",
- active: false
+ active: false,
+ authStrategy: AuthStrategy.api_key
},
'hive': {
- apiUrl: '',
scopes: '',
- authBaseUrl: 'https://api.github.com',
+ urls: {
+ docsUrl: "",
+ apiUrl: 'https://app.hive.com/api/v1',
+ },
logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRqz0aID6B-InxK_03P7tCtqpXNXdawBcro67CyEE0I5g&s',
description: "Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users",
- active: false
+ active: false,
+ authStrategy: AuthStrategy.api_key
},
+ //todo
'intercom': {
- apiUrl: '',
scopes: '',
- authBaseUrl: 'https://api.github.com',
+ urls: {
+ docsUrl: "",
+ apiUrl: '',
+ },
logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRqz0aID6B-InxK_03P7tCtqpXNXdawBcro67CyEE0I5g&s',
description: "Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users",
active: false
},
+ //todo
'ironclad': {
- apiUrl: '',
scopes: '',
- authBaseUrl: 'https://api.github.com',
+ urls: {
+ docsUrl: "",
+ apiUrl: '',
+ },
logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRqz0aID6B-InxK_03P7tCtqpXNXdawBcro67CyEE0I5g&s',
description: "Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users",
- active: false
+ active: false,
+ authStrategy: AuthStrategy.api_key
},
'kustomer': {
- apiUrl: '',
scopes: '',
- authBaseUrl: 'https://api.github.com',
+ urls: {
+ docsUrl: "",
+ apiUrl: 'https://api.kustomerapp.com',
+ },
logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRqz0aID6B-InxK_03P7tCtqpXNXdawBcro67CyEE0I5g&s',
description: "Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users",
- active: false
+ active: false,
+ authStrategy: AuthStrategy.api_key
},
+ //todo
'pivotal_tracker': {
- apiUrl: '',
scopes: '',
- authBaseUrl: 'https://api.github.com',
+ urls: {
+ docsUrl: "",
+ apiUrl: '',
+ },
logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRqz0aID6B-InxK_03P7tCtqpXNXdawBcro67CyEE0I5g&s',
description: "Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users",
active: false
},
+ //todo
'rally': {
- apiUrl: '',
scopes: '',
- authBaseUrl: 'https://api.github.com',
+ urls: {
+ docsUrl: "",
+ apiUrl: '',
+ },
logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRqz0aID6B-InxK_03P7tCtqpXNXdawBcro67CyEE0I5g&s',
description: "Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users",
active: false
},
'reamaze': {
- apiUrl: '',
scopes: '',
- authBaseUrl: 'https://api.github.com',
+ urls: {
+ docsUrl: "",
+ apiUrl: '/api/v1',
+ },
logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRqz0aID6B-InxK_03P7tCtqpXNXdawBcro67CyEE0I5g&s',
description: "Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users",
- active: false
+ active: false,
+ authStrategy: AuthStrategy.api_key
},
+ //todo
'salesforce': {
- apiUrl: '',
scopes: '',
- authBaseUrl: 'https://api.github.com',
+ urls: {
+ docsUrl: "",
+ apiUrl: '',
+ },
logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRqz0aID6B-InxK_03P7tCtqpXNXdawBcro67CyEE0I5g&s',
description: "Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users",
active: false
},
+ //todo
'servicenow': {
- apiUrl: '',
scopes: '',
- authBaseUrl: 'https://api.github.com',
+ urls: {
+ docsUrl: "",
+ apiUrl: '',
+ },
logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRqz0aID6B-InxK_03P7tCtqpXNXdawBcro67CyEE0I5g&s',
description: "Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users",
active: false
},
'shortcut': {
- apiUrl: '',
scopes: '',
- authBaseUrl: 'https://api.github.com',
+ urls: {
+ docsUrl: "",
+ apiUrl: 'https://api.app.shortcut.com',
+ },
logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRqz0aID6B-InxK_03P7tCtqpXNXdawBcro67CyEE0I5g&s',
description: "Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users",
- active: false
+ active: false,
+ authStrategy: AuthStrategy.api_key
},
+ //todo
'spotdraft': {
- apiUrl: '',
scopes: '',
- authBaseUrl: 'https://api.github.com',
+ urls: {
+ docsUrl: "",
+ apiUrl: '',
+ },
logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRqz0aID6B-InxK_03P7tCtqpXNXdawBcro67CyEE0I5g&s',
description: "Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users",
active: false
},
+ //todo
'teamwork': {
- apiUrl: '',
scopes: '',
- authBaseUrl: 'https://api.github.com',
+ urls: {
+ docsUrl: "",
+ apiUrl: '',
+ },
logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRqz0aID6B-InxK_03P7tCtqpXNXdawBcro67CyEE0I5g&s',
description: "Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users",
active: false
},
+ //todo
'trello': {
- apiUrl: '',
scopes: '',
- authBaseUrl: 'https://api.github.com',
+ urls: {
+ docsUrl: "",
+ apiUrl: 'https://api.app.shortcut.com',
+ },
logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRqz0aID6B-InxK_03P7tCtqpXNXdawBcro67CyEE0I5g&s',
description: "Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users",
active: false
},
'wrike': {
- apiUrl: '',
scopes: '',
- authBaseUrl: 'https://api.github.com',
+ urls: {
+ docsUrl: "",
+ apiUrl: '/api/v4',
+ authBaseUrl: 'https://login.wrike.com/oauth2/authorize/v4',
+ },
logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRqz0aID6B-InxK_03P7tCtqpXNXdawBcro67CyEE0I5g&s',
description: "Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users",
- active: false
+ active: false,
+ authStrategy: AuthStrategy.oauth2
},
'zoho_bugtracker': {
- apiUrl: '',
scopes: '',
- authBaseUrl: 'https://api.github.com',
+ urls: {
+ docsUrl: "",
+ apiUrl: '',
+ },
logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRqz0aID6B-InxK_03P7tCtqpXNXdawBcro67CyEE0I5g&s',
description: "Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users",
active: false
},
'zoho_desk': {
- apiUrl: '',
scopes: '',
- authBaseUrl: 'https://api.github.com',
+ urls: {
+ docsUrl: "",
+ apiUrl: '',
+ },
logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRqz0aID6B-InxK_03P7tCtqpXNXdawBcro67CyEE0I5g&s',
description: "Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users",
active: false
@@ -542,1071 +731,1364 @@ export const providersConfig: ProvidersConfig = {
},
'accounting': {
'pennylane': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: 'https://app.pennylane.com/api/external/v1',
+ authBaseUrl: 'https://app.pennylane.com/oauth/authorize',
+ },
logoPath: 'https://cdn-images-1.medium.com/max/1200/1*wk7CNGik_1Szbt7s1fNZxA.png',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
- active: false
+ active: false,
+ authStrategy: AuthStrategy.oauth2
},
'freshbooks': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: 'https://api.freshbooks.com',
+ authBaseUrl: 'https://auth.freshbooks.com/oauth/authorize',
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
- active: false
+ active: false,
+ authStrategy: AuthStrategy.oauth2
},
+ //todo
'clearbooks': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: "",
+ authBaseUrl: '',
+ },
logoPath: 'https://s3-eu-west-1.amazonaws.com/clearbooks-marketing/media-centre/MediaCentre/clear-books/CMYK/icon/clear-books-icon-cmyk.png',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'freeagent': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: 'https://api.freeagent.com/v2',
+ authBaseUrl: 'https://api.freeagent.com/v2/approve_app',
+ },
logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQU-fob0b9pBNQdm80usnYa2yWdagm3eeBDH-870vSmfg&s',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
- active: false
+ active: false,
+ authStrategy: AuthStrategy.oauth2
},
'sage': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: 'https://api.accounting.sage.com/v3.1',
+ authBaseUrl: 'https://www.sageone.com/oauth2/auth/central?filter=apiv3.1',
+ },
logoPath: 'https://upload.wikimedia.org/wikipedia/en/thumb/b/b7/Sage_Group_logo_2022.svg/2560px-Sage_Group_logo_2022.svg.png',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
- active: false
+ active: false,
+ authStrategy: AuthStrategy.oauth2
},
+ //todo
'sage_intacct': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: '',
+ authBaseUrl: '',
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
+ //todo
'microsoft_dynamics': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: '',
+ authBaseUrl: '',
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'moneybird': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: 'https://moneybird.com/api/v2',
+ authBaseUrl: 'https://moneybird.com/oauth/authorize',
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
- active: false
+ active: false,
+ authStrategy: AuthStrategy.oauth2
},
+ //todo
'netsuite': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: '',
+ authBaseUrl: '',
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'quickbooks': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: 'https://quickbooks.api.intuit.com/v3',
+ authBaseUrl: 'https://appcenter.intuit.com/connect/oauth2',
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
- active: false
+ active: false,
+ authStrategy: AuthStrategy.oauth2
},
+ //todo
'workday': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: '',
+ authBaseUrl: '',
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'wave_financial': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: 'https://gql.waveapps.com/graphql/public',
+ authBaseUrl: 'https://api.waveapps.com/oauth2/authorize/',
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
- active: false
+ active: false,
+ authStrategy: AuthStrategy.oauth2
},
},
+ //TODO
'marketing_automation': {
'active_campaign': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'customerio': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'getresponse': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'hubspot_marketing_hub': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'keap': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'klaviyo': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'mailchimp': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'messagebird': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'podium': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'sendgrid': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'sendinblue': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
},
+ //TODO
'ats': {
'applicantstack': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'ashby': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'bamboohr': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'breezy': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'bullhorn': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'cats': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'clayhr': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'clockwork': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'comeet': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'cornerstone_talentlink': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'engage_ats': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'eploy': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'fountain': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'freshteam': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'greenhouse': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'greenhouse_job_boards': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'harbour_ats': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'homerun': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'hrcloud': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'icims': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'infinite_brassring': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'jazzhr': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'jobadder': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'jobscore': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'jobvite': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'lano': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'lever': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'occupop': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'oracle_fusion': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'oracle_taleo': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'personio_recruiting': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'pinpoint': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'polymer': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'recruiterflow': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'recruitive': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'sage_hr': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'sap_successfactors': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'smartrecruiters': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'talentlyft': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'talentreef': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'teamtailor': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'tellent': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'tribepad': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'ukg_pro_recruiting': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'workable': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'workday': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'zoho_recruit': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
},
+ //TODO
'hris': {
'7shifts': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'adp_workforce_now': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'alexishr': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'alliancehcm': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'altera_payroll': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'bamboohr': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'breathe': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'ceridian_dayforce': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'charlie': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'charthop': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'clayhr': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'cyberark': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'deel': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'employment_hero': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'factorial': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'freshteam': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'google_workspace': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'gusto': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'hibob': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'hrcloud': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'hrpartner': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'humaans': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'humi': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'insperity_premier': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'active_campaign': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'intellli_hr': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'iris_cascade': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'jumpcloud': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'justworks': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'kallidus': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'keka': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'kenjo': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'lano': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'lucca': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'microsoft_entra_id': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'namely': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'nmbrs': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'officient': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'okta': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'onelogin': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'oracle_hcm': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'oyster_hr': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'paycaptain': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'paychex': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'paycor': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'payfit': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'paylocity': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'people_hr': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'personio': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'pingone': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'proliant': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'remote': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'sage_hr': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'sap_successfactors': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'sesame': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'square_payroll': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'trinet': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'trinet_hr_platform': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'ukg_pro': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'ukg_pro_workforce': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'ukg_ready': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'workday': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
},
'zoho_people': {
- apiUrl: '',
scopes: '',
- authBaseUrl: '',
+ urls: {
+ docsUrl: "",
+ apiUrl: ""
+ },
logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM',
description: "Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users",
active: false
@@ -1642,9 +2124,12 @@ export const getDescription = (name: string): string | null => {
type Provider = {
name: string;
- apiUrl: string;
+ urls: {
+ docsUrl: string;
+ apiUrl: string;
+ authBaseUrl?: string | null;
+ };
scopes: string;
- authBaseUrl: string;
logoPath: string;
description?: string;
};
@@ -1653,9 +2138,12 @@ export function providersArray(vertical: string): Provider[] {
const activeProviders = getActiveProvidersForVertical(vertical);
return Object.entries(activeProviders).map(([providerName, config]) => ({
name: providerName,
- apiUrl: config.apiUrl,
+ urls: {
+ docsUrl: config.urls.docsUrl,
+ apiUrl: config.urls.apiUrl,
+ authBaseUrl: config.urls.authBaseUrl,
+ },
scopes: config.scopes,
- authBaseUrl: config.authBaseUrl,
logoPath: config.logoPath,
description: config.description,
}));
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 86b053edb..3937b5d3c 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -511,6 +511,9 @@ importers:
dotenv:
specifier: ^16.3.1
version: 16.4.5
+ randomstring:
+ specifier: ^1.3.0
+ version: 1.3.0
devDependencies:
'@nestjs/common':
specifier: ^10.0.0
@@ -10863,12 +10866,23 @@ packages:
engines: {node: '>=10'}
dev: false
+ /randombytes@2.0.3:
+ resolution: {integrity: sha512-lDVjxQQFoCG1jcrP06LNo2lbWp4QTShEXnhActFBwYuHprllQV6VUpwreApsYqCgD+N1mHoqJ/BI/4eV4R2GYg==}
+ dev: false
+
/randombytes@2.1.0:
resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
dependencies:
safe-buffer: 5.2.1
dev: true
+ /randomstring@1.3.0:
+ resolution: {integrity: sha512-gY7aQ4i1BgwZ8I1Op4YseITAyiDiajeZOPQUbIq9TPGPhUm5FX59izIaOpmKbME1nmnEiABf28d9K2VSii6BBg==}
+ hasBin: true
+ dependencies:
+ randombytes: 2.0.3
+ dev: false
+
/range-parser@1.2.1:
resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
engines: {node: '>= 0.6'}