diff --git a/.github/workflows/webflow-sync.yaml b/.github/workflows/webflow-sync.yaml index 5c872426925..dd8e36f51d4 100644 --- a/.github/workflows/webflow-sync.yaml +++ b/.github/workflows/webflow-sync.yaml @@ -5,7 +5,7 @@ on: branches: - master paths: - - packages/shared/providers.yaml + - packages/providers/providers.yaml - docs-v2/integrations/all/*.md workflow_dispatch: diff --git a/docker-compose.yaml b/docker-compose.yaml index ff422615e4b..6e7af3091cb 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -44,7 +44,7 @@ services: - NANGO_LOGS_ES_PWD - FLAG_SERVE_CONNECT_UI=${FLAG_SERVE_CONNECT_UI:-true} volumes: - - './packages/shared/providers.yaml:/usr/nango-server/src/packages/shared/providers.yaml' + - './packages/providers/providers.yaml:/usr/nango-server/src/packages/providers/providers.yaml' restart: always ports: - '${SERVER_PORT:-3003}:${SERVER_PORT:-3003}' diff --git a/docs-v2/reference/api-configuration.mdx b/docs-v2/reference/api-configuration.mdx index b13fd15d5e4..dfc57939b20 100644 --- a/docs-v2/reference/api-configuration.mdx +++ b/docs-v2/reference/api-configuration.mdx @@ -4,7 +4,7 @@ sidebarTitle: 'API config (providers.yaml)' icon: 'network-wired' --- -API configurations are listed in the `providers.yaml` file, located in the [Nango GitHub repository](https://github.com/NangoHQ/nango/blob/master/packages/shared/providers.yaml). +API configurations are listed in the `providers.yaml` file, located in the [Nango GitHub repository](https://github.com/NangoHQ/nango/blob/master/packages/providers/providers.yaml). # Examples diff --git a/package-lock.json b/package-lock.json index b75c03cdfc7..cc52df1a603 100644 --- a/package-lock.json +++ b/package-lock.json @@ -35163,7 +35163,8 @@ "@babel/traverse": "^7.22.5", "@babel/types": "^7.22.5", "@nangohq/nango-yaml": "0.48.3", - "@nangohq/shared": "^0.48.3", + "@nangohq/node": "0.48.3", + "@nangohq/runner-sdk": "0.48.3", "@swc/core": "^1.5.25", "ajv": "^8.17.1", "ajv-errors": "^3.0.0", @@ -35651,7 +35652,6 @@ "@nangohq/nango-runner": "file:../runner", "@nangohq/records": "file:../records", "@nangohq/shared": "file:../shared", - "@nangohq/types": "file:../types", "@nangohq/utils": "file:../utils", "@nangohq/webhooks": "file:../webhooks", "axios": "^1.7.9", @@ -35664,6 +35664,7 @@ "zod": "3.24.1" }, "devDependencies": { + "@nangohq/types": "file:../types", "@types/node": "^20.12.2", "nodemon": "3.1.9", "type-fest": "4.32.0", @@ -36608,6 +36609,9 @@ "version": "1.0.0", "license": "SEE LICENSE IN LICENSE FILE IN GIT REPOSITORY", "dependencies": { + "@nangohq/node": "file:../node-client", + "@nangohq/providers": "file:../providers", + "@nangohq/runner-sdk": "file:../runner-sdk", "@nangohq/shared": "file:../shared", "@nangohq/utils": "file:../utils", "@trpc/client": "^10.45.1", @@ -36623,6 +36627,7 @@ "zod": "3.24.1" }, "devDependencies": { + "@nangohq/database": "file:../database", "@nangohq/types": "file:../types", "@types/connect-timeout": "0.0.39", "@types/node": "20.12.2", @@ -36631,6 +36636,7 @@ } }, "packages/runner-sdk": { + "name": "@nangohq/runner-sdk", "version": "0.48.3", "dependencies": { "@nangohq/node": "0.48.3", @@ -37280,8 +37286,8 @@ "@datadog/datadog-api-client": "1.26.0", "@hapi/boom": "^10.0.1", "@nangohq/database": "file:../database", - "@nangohq/nango-yaml": "0.48.3", - "@nangohq/node": "^0.48.3", + "@nangohq/nango-yaml": "file:../nango-yaml", + "@nangohq/providers": "file:../providers", "@nangohq/utils": "file:../utils", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", @@ -37308,7 +37314,7 @@ "devDependencies": { "@nangohq/logs": "file:../logs", "@nangohq/nango-orchestrator": "file:../orchestrator", - "@nangohq/types": "0.48.3", + "@nangohq/types": "file:../types", "@types/braintree": "^3.3.12", "@types/js-yaml": "^4.0.5", "@types/json-schema": "7.0.15", diff --git a/packages/cli/lib/services/__snapshots__/model.service.unit.test.ts.snap b/packages/cli/lib/services/__snapshots__/model.service.unit.test.ts.snap index bc046f94f3b..dfd21c30800 100644 --- a/packages/cli/lib/services/__snapshots__/model.service.unit.test.ts.snap +++ b/packages/cli/lib/services/__snapshots__/model.service.unit.test.ts.snap @@ -41,18 +41,18 @@ exports[`buildModelTs > should return empty (with sdk) 1`] = ` // ------ SDK -import { Nango } from '@nangohq/node'; -import type { AxiosInstance, AxiosInterceptorManager, AxiosRequestConfig, AxiosResponse } from 'axios'; -import { AxiosError } from 'axios'; +import type { Nango } from '@nangohq/node'; +import type { AxiosInstance, AxiosInterceptorManager, AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios'; import type { ApiEndUser, DBSyncConfig, DBTeam, GetPublicIntegration, RunnerFlags } from '@nangohq/types'; + export declare const oldLevelToNewLevel: { - readonly debug: "debug"; - readonly info: "info"; - readonly warn: "warn"; - readonly error: "error"; - readonly verbose: "debug"; - readonly silly: "debug"; - readonly http: "info"; + readonly debug: 'debug'; + readonly info: 'info'; + readonly warn: 'warn'; + readonly error: 'error'; + readonly verbose: 'debug'; + readonly silly: 'debug'; + readonly http: 'info'; }; type LogLevel = 'info' | 'debug' | 'error' | 'warn' | 'http' | 'verbose' | 'silly'; type ParamEncoder = (value: any, defaultEncoder: (value: any) => any) => any; @@ -202,7 +202,7 @@ interface JwtCredentials { type: AuthModes['Jwt']; privateKeyId?: string; issuerId?: string; - privateKey: { + privateKey:{ id: string; secret: string; } | string; @@ -298,14 +298,16 @@ export interface NangoProps { dryRun?: boolean; track_deletes?: boolean; attributes?: object | undefined; - logMessages?: { - counts: { - updated: number; - added: number; - deleted: number; - }; - messages: unknown[]; - } | undefined; + logMessages?: + | { + counts: { + updated: number; + added: number; + deleted: number; + }; + messages: unknown[]; + } + | undefined; rawSaveOutput?: Map | undefined; rawDeleteOutput?: Map | undefined; stubbedMetadata?: Metadata | undefined; @@ -354,9 +356,14 @@ export declare class NangoAction { ActionError: typeof ActionError; private memoizedConnections; private memoizedIntegration; - constructor(config: NangoProps, { persistApi }?: { - persistApi: AxiosInstance; - }); + constructor( + config: NangoProps, + { + persistApi + }?: { + persistApi: AxiosInstance; + } + ); protected stringify(): string; private proxyConfig; protected throwIfAborted(): void; @@ -393,15 +400,26 @@ export declare class NangoAction { * await nango.log('This is a log message', { level: 'error' }) * \`\`\` */ - log(message: any, options?: { - level?: LogLevel; - } | { - [key: string]: any; - level?: never; - }): Promise; - log(message: string, ...args: [any, { - level?: LogLevel; - }]): Promise; + log( + message: any, + options?: + | { + level?: LogLevel; + } + | { + [key: string]: any; + level?: never; + } + ): Promise; + log( + message: string, + ...args: [ + any, + { + level?: LogLevel; + } + ] + ): Promise; getEnvironmentVariables(): Promise; getFlowAttributes(): A | null; paginate(config: ProxyConfiguration): AsyncGenerator; @@ -413,14 +431,16 @@ export declare class NangoAction { export declare class NangoSync extends NangoAction { lastSyncDate?: Date; track_deletes: boolean; - logMessages?: { - counts: { - updated: number; - added: number; - deleted: number; - }; - messages: unknown[]; - } | undefined; + logMessages?: + | { + counts: { + updated: number; + added: number; + deleted: number; + }; + messages: unknown[]; + } + | undefined; rawSaveOutput?: Map; rawDeleteOutput?: Map; stubbedMetadata?: Metadata | undefined; diff --git a/packages/cli/lib/services/dryrun.service.ts b/packages/cli/lib/services/dryrun.service.ts index ad39b696efd..8872b7e3baf 100644 --- a/packages/cli/lib/services/dryrun.service.ts +++ b/packages/cli/lib/services/dryrun.service.ts @@ -1,12 +1,11 @@ +/* eslint-disable no-console */ import promptly from 'promptly'; import fs from 'node:fs'; import { AxiosError } from 'axios'; import type { AxiosResponse } from 'axios'; import chalk from 'chalk'; -import type { NangoProps } from '@nangohq/shared'; -import type { DBSyncConfig, Metadata, ParsedNangoAction, ParsedNangoSync, RunnerOutput, ScriptFileType } from '@nangohq/types'; -import { NangoError, validateData, NangoSync, ActionError } from '@nangohq/shared'; +import type { DBSyncConfig, Metadata, NangoProps, ParsedNangoAction, ParsedNangoSync, ScriptFileType } from '@nangohq/types'; import type { GlobalOptions } from '../types.js'; import { parseSecretKey, printDebug, hostport, getConnection, getConfig } from '../utils.js'; import { compileAllFiles } from './compile.service.js'; @@ -20,6 +19,8 @@ import * as crypto from 'crypto'; import * as zod from 'zod'; import { Buffer } from 'buffer'; import { serializeError } from 'serialize-error'; +import { ActionError, InvalidActionInputSDKError, InvalidActionOutputSDKError, SDKError, validateData } from '@nangohq/runner-sdk'; +import { NangoActionCLI, NangoSyncCLI } from './sdk.js'; interface RunArgs extends GlobalOptions { sync: string; @@ -273,11 +274,6 @@ export class DryRunService { } } - const logMessages = { - counts: { updated: 0, added: 0, deleted: 0 }, - messages: [] - }; - const jsonSchema = loadSchemaJson({ fullPath: this.fullPath }); if (!jsonSchema) { console.log(chalk.red('Failed to load schema.json')); @@ -323,11 +319,7 @@ export class DryRunService { nangoConnectionId: nangoConnection.id as number, syncId: 'dryrun-sync', lastSyncDate: lastSyncDate as Date, - dryRun: true, - logMessages, - stubbedMetadata, syncConfig, - dryRunService: new DryRunService({ environment, returnOutput: true, fullPath: this.fullPath, validation: this.validation }), debug, runnerFlags: { validateActionInput: this.validation, // irrelevant for cli @@ -339,9 +331,6 @@ export class DryRunService { endUser: null }; if (options.saveResponses) { - nangoProps.rawSaveOutput = new Map(); - nangoProps.rawDeleteOutput = new Map(); - nangoProps.axios = { response: { onFulfilled: (response: AxiosResponse) => @@ -356,16 +345,17 @@ export class DryRunService { syncName, nangoProps, loadLocation: './', - input: normalizedInput + input: normalizedInput, + stubbedMetadata: stubbedMetadata }); console.log('---'); if (results.error) { const err = results.error; console.error(chalk.red('An error occurred during execution')); - if (err instanceof Error && 'type' in err && 'payload' in err) { - console.error(chalk.red(err.message), chalk.gray(`(${err.type})`)); - if (err.type === 'invalid_action_output' || err.type === 'invalid_action_input' || err.type === 'invalid_sync_record') { + if (err instanceof SDKError) { + console.error(chalk.red(err.message), chalk.gray(`(${err.code})`)); + if (err.code === 'invalid_action_output' || err.code === 'invalid_action_input' || err.code === 'invalid_sync_record') { displayValidationError(err.payload as any); return; } @@ -384,7 +374,7 @@ export class DryRunService { console.log(chalk.gray('no output')); resultOutput.push(chalk.gray('no output')); } else { - console.log(JSON.stringify(results.response, null, 2)); + console.log(JSON.stringify(results.response.output, null, 2)); if (options.saveResponses) { const responseDirectoryPrefix = process.env['NANGO_MOCKS_RESPONSE_DIRECTORY'] ?? ''; const directoryName = `${responseDirectoryPrefix}${providerConfigKey}`; @@ -396,6 +386,7 @@ export class DryRunService { } } + const logMessages = results.response?.nango && results.response.nango instanceof NangoSyncCLI && results.response.nango.logMessages; if (logMessages && logMessages.messages.length > 0) { const messages = logMessages.messages; let index = 0; @@ -428,21 +419,22 @@ export class DryRunService { } } - if (options.saveResponses) { + if (options.saveResponses && results.response?.nango && results.response?.nango instanceof NangoSyncCLI) { const responseDirectoryPrefix = process.env['NANGO_MOCKS_RESPONSE_DIRECTORY'] ?? ''; const directoryName = `${responseDirectoryPrefix}${providerConfigKey}`; + const nango = results.response.nango; if (scriptInfo?.output) { for (const model of scriptInfo.output) { responseSaver.ensureDirectoryExists(`${directoryName}/mocks/${syncName}/${model}`); - if (nangoProps.rawSaveOutput) { + { const filePath = `${directoryName}/mocks/${syncName}/${model}/batchSave.json`; - const modelData = nangoProps.rawSaveOutput.get(model) || []; + const modelData = nango.rawSaveOutput.get(model) || []; fs.writeFileSync(filePath, JSON.stringify(modelData, null, 2)); } - if (nangoProps.rawDeleteOutput) { + { const filePath = `${directoryName}/mocks/${syncName}/${model}/batchDelete.json`; - const modelData = nangoProps.rawDeleteOutput.get(model) || []; + const modelData = nango.rawDeleteOutput.get(model) || []; fs.writeFileSync(filePath, JSON.stringify(modelData, null, 2)); } } @@ -464,23 +456,32 @@ export class DryRunService { syncName, nangoProps, loadLocation, - input + input, + stubbedMetadata }: { syncName: string; nangoProps: NangoProps; loadLocation: string; input: object; - }): Promise { - const nango = new NangoSync(nangoProps); + stubbedMetadata?: Metadata; + }): Promise< + { success: false; error: any; response: null } | { success: true; error: null; response: { output: any; nango: NangoSyncCLI | NangoActionCLI } } + > { + const drs = new DryRunService({ environment: nangoProps.environmentName!, returnOutput: true, fullPath: this.fullPath, validation: this.validation }); + const nango = + nangoProps.scriptType === 'sync' || nangoProps.scriptType === 'webhook' + ? new NangoSyncCLI(nangoProps, { dryRunService: drs, stubbedMetadata }) + : new NangoActionCLI(nangoProps, { dryRunService: drs }); + try { - await nango.log(`Executing -> integration:"${nangoProps.provider}" script:"${syncName}"`); + nango.log(`Executing -> integration:"${nangoProps.provider}" script:"${syncName}"`); const script = getIntegrationFile(syncName, nangoProps.providerConfigKey, loadLocation); const isAction = nangoProps.scriptType === 'action'; if (!script) { const content = `Unable to find script file for "${syncName}"`; - return { success: false, error: new NangoError(content, 500), response: null }; + return { success: false, error: new Error(content), response: null }; } const filename = `${syncName}-${nangoProps.providerConfigKey}.js`; @@ -522,7 +523,7 @@ export class DryRunService { if (!scriptExports.default || !(typeof scriptExports.default === 'function')) { const content = `There is no default export that is a function for ${syncName}`; - return { success: false, error: new NangoError(content, 500), response: null }; + return { success: false, error: new Error(content), response: null }; } if (isAction) { @@ -534,12 +535,12 @@ export class DryRunService { jsonSchema: nangoProps.syncConfig.models_json_schema }); if (Array.isArray(valInput)) { - await nango.log('Invalid action input. Use `--validation` option to see the details', { level: 'warn' }); + nango.log('Invalid action input. Use `--validation` option to see the details', { level: 'warn' }); if (nangoProps.runnerFlags.validateActionInput) { return { success: false, response: null, - error: new NangoError('invalid_action_input', { data: input, validation: valInput, model: nangoProps.syncConfig.input }) + error: new InvalidActionInputSDKError({ data: input, validation: valInput, model: nangoProps.syncConfig.input }) }; } } @@ -556,21 +557,21 @@ export class DryRunService { jsonSchema: nangoProps.syncConfig.models_json_schema }); if (Array.isArray(valOutput)) { - await nango.log('Invalid action output. Use `--validation` option to see the details', { level: 'warn' }); + nango.log('Invalid action output. Use `--validation` option to see the details', { level: 'warn' }); if (nangoProps.runnerFlags.validateActionOutput) { return { success: false, response: null, - error: new NangoError('invalid_action_output', { data: output, validation: valOutput, model: modelNameOutput }) + error: new InvalidActionOutputSDKError({ data: output, validation: valOutput, model: modelNameOutput }) }; } } - return { success: true, error: null, response: output }; + return { success: true, error: null, response: { output, nango } }; } const results = await scriptExports.default(nango); - return { success: true, error: null, response: results }; + return { success: true, error: null, response: { output: results, nango } }; } catch (err) { if (err instanceof ActionError) { return { @@ -582,8 +583,6 @@ export class DryRunService { }, response: null }; - } else if (err instanceof NangoError) { - return { success: false, error: err, response: null }; } else if (err instanceof AxiosError) { if (err.response?.data) { const errorResponse = err.response.data.payload || err.response.data; @@ -633,11 +632,11 @@ export class DryRunService { } } catch (err) { const errorMessage = JSON.stringify(err, ['message', 'name', 'stack'], 2); - const content = `The script failed to load for ${syncName} with the following error: ${errorMessage}`; + const content = `The script failed to load for ${syncName} with the following error`; - return { success: false, error: new NangoError(content, 500), response: null }; + return { success: false, error: new Error(content, { cause: errorMessage }), response: null }; } finally { - await nango.log(`Done`); + nango.log(`Done`); } } } diff --git a/packages/cli/lib/services/model.service.ts b/packages/cli/lib/services/model.service.ts index f106f1ac0f3..d14cb6a188a 100644 --- a/packages/cli/lib/services/model.service.ts +++ b/packages/cli/lib/services/model.service.ts @@ -161,7 +161,7 @@ export function fieldToTypescript({ field }: { field: NangoModelField }): string * Generate SDK types */ export function generateSDKTypes() { - const filePath = resolve('@nangohq/shared/dist/sdk/sync.d.ts', import.meta.url); + const filePath = resolve('@nangohq/runner-sdk/models.d.ts', import.meta.url); const typesContent = fs.readFileSync(new URL(filePath), 'utf8'); return ` diff --git a/packages/cli/lib/services/sdk.ts b/packages/cli/lib/services/sdk.ts new file mode 100644 index 00000000000..1b85c076e67 --- /dev/null +++ b/packages/cli/lib/services/sdk.ts @@ -0,0 +1,209 @@ +import { Nango } from '@nangohq/node'; +import type { ProxyConfiguration } from '@nangohq/runner-sdk'; +import { InvalidRecordSDKError, NangoActionBase, NangoSyncBase } from '@nangohq/runner-sdk'; +import type { AdminAxiosProps } from '@nangohq/node'; +import type { DryRunServiceInterface, Metadata, NangoProps, UserLogParameters } from '@nangohq/types'; +import type { AxiosResponse } from 'axios'; + +const logLevelToLogger = { + info: 'info', + debug: 'debug', + error: 'error', + warn: 'warn', + http: 'info', + verbose: 'debug', + silly: 'debug' +} as const; + +export class NangoActionCLI extends NangoActionBase { + nango: Nango; + dryRunService: DryRunServiceInterface; + dryRun = true; + + constructor(props: NangoProps, cliProps: { dryRunService: DryRunServiceInterface }) { + super(props); + + this.dryRunService = cliProps.dryRunService; + + const axiosSettings: AdminAxiosProps = { + userAgent: 'sdk' + }; + + if (props.axios?.response) { + axiosSettings.interceptors = { + response: { + onFulfilled: props.axios.response.onFulfilled, + onRejected: props.axios.response.onRejected + } + }; + } + + this.nango = new Nango({ isSync: false, dryRun: true, ...props }, axiosSettings); + } + + public override proxy(config: ProxyConfiguration): Promise> { + if (!config.method) { + config.method = 'GET'; + } + + return this.nango.proxy(config); + } + + public override log(...args: [...any]): void { + if (args.length === 0) { + return; + } + + const lastArg = args[args.length - 1]; + const isUserDefinedLevel = (object: UserLogParameters): boolean => { + return lastArg && typeof lastArg === 'object' && 'level' in object; + }; + const userDefinedLevel: UserLogParameters | undefined = isUserDefinedLevel(lastArg) ? lastArg : undefined; + + if (userDefinedLevel) { + args.pop(); + } + + const level = userDefinedLevel?.level ?? 'info'; + + const logLevel = logLevelToLogger[level] ?? 'info'; + + if (args.length > 1 && 'type' in args[1] && args[1].type === 'http') { + console[logLevel](args[0], { status: args[1]?.response?.code || 'xxx' }); + } else { + console[logLevel](...args); + } + } + + public triggerSync(_providerConfigKey: string, connectionId: string, syncName: string, _fullResync?: boolean): Promise { + return this.dryRunService.run({ + sync: syncName, + connectionId, + autoConfirm: true, + debug: false + }); + } +} + +export class NangoSyncCLI extends NangoSyncBase { + nango: Nango; + dryRunService: DryRunServiceInterface; + dryRun = true; + + logMessages: { counts: { updated: number; added: number; deleted: number }; messages: unknown[] } = { + counts: { updated: 0, added: 0, deleted: 0 }, + messages: [] + }; + + rawSaveOutput = new Map(); + rawDeleteOutput = new Map(); + stubbedMetadata?: Metadata | undefined = undefined; + + constructor(props: NangoProps, cliProps: { stubbedMetadata?: Metadata | undefined; dryRunService: DryRunServiceInterface }) { + super(props); + + if (cliProps.stubbedMetadata) { + this.stubbedMetadata = cliProps.stubbedMetadata; + } + + this.dryRunService = cliProps.dryRunService; + + const axiosSettings: AdminAxiosProps = { + userAgent: 'sdk' + }; + + if (props.axios?.response) { + axiosSettings.interceptors = { + response: { + onFulfilled: props.axios.response.onFulfilled, + onRejected: props.axios.response.onRejected + } + }; + } + + this.nango = new Nango({ isSync: true, dryRun: true, ...props }, axiosSettings); + } + + // Can't double extends + proxy = NangoActionCLI['prototype']['proxy']; + log = NangoActionCLI['prototype']['log']; + triggerSync = NangoActionCLI['prototype']['triggerSync']; + + public batchSave(results: T[], model: string) { + if (!results || results.length === 0) { + console.info('batchSave received an empty array. No records to save.'); + return true; + } + + // Validate records + const hasErrors = this.validateRecords(model, results); + + if (hasErrors.length > 0) { + this.log('Invalid record payload. Use `--validation` option to see the details', { level: 'warn' }); + if (this.runnerFlags?.validateSyncRecords) { + throw new InvalidRecordSDKError({ ...hasErrors[0], model }); + } + } + + this.logMessages?.messages.push(`A batch save call would save the following data to the ${model} model:`); + for (const msg of results) { + this.logMessages?.messages.push(msg); + } + if (this.logMessages && this.logMessages.counts) { + this.logMessages.counts.added = Number(this.logMessages.counts.added) + results.length; + } + if (this.rawSaveOutput) { + if (!this.rawSaveOutput.has(model)) { + this.rawSaveOutput.set(model, []); + } + this.rawSaveOutput.get(model)?.push(...results); + } + return true; + } + + public batchDelete(results: T[], model: string) { + if (!results || results.length === 0) { + console.info('batchDelete received an empty array. No records to delete.'); + return true; + } + + this.logMessages?.messages.push(`A batch delete call would delete the following data:`); + for (const msg of results) { + this.logMessages?.messages.push(msg); + } + if (this.logMessages && this.logMessages.counts) { + this.logMessages.counts.deleted = Number(this.logMessages.counts.deleted) + results.length; + } + if (this.rawDeleteOutput) { + if (!this.rawDeleteOutput.has(model)) { + this.rawDeleteOutput.set(model, []); + } + this.rawDeleteOutput.get(model)?.push(...results); + } + return true; + } + + public batchUpdate(results: T[], model: string) { + if (!results || results.length === 0) { + console.info('batchUpdate received an empty array. No records to update.'); + return true; + } + + this.logMessages?.messages.push(`A batch update call would update the following data to the ${model} model:`); + for (const msg of results) { + this.logMessages?.messages.push(msg); + } + if (this.logMessages && this.logMessages.counts) { + this.logMessages.counts.updated = Number(this.logMessages.counts.updated) + results.length; + } + return true; + } + + public override getMetadata(): Promise { + if (this.stubbedMetadata) { + return Promise.resolve(this.stubbedMetadata as TMetadata); + } + + return super.getMetadata(); + } +} diff --git a/packages/cli/package.json b/packages/cli/package.json index a4da4d8ad88..3479fa9f5d9 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -24,8 +24,9 @@ "@babel/parser": "^7.22.5", "@babel/traverse": "^7.22.5", "@babel/types": "^7.22.5", + "@nangohq/node": "0.48.3", "@nangohq/nango-yaml": "0.48.3", - "@nangohq/shared": "^0.48.3", + "@nangohq/runner-sdk": "0.48.3", "@swc/core": "^1.5.25", "ajv": "^8.17.1", "ajv-errors": "^3.0.0", diff --git a/packages/cli/tsconfig.json b/packages/cli/tsconfig.json index 4effe8840d5..53dfd06d4dc 100644 --- a/packages/cli/tsconfig.json +++ b/packages/cli/tsconfig.json @@ -6,7 +6,7 @@ }, "references": [ { - "path": "../shared" + "path": "../runner-sdk" }, { "path": "../types" diff --git a/packages/jobs/lib/execution/action.ts b/packages/jobs/lib/execution/action.ts index 113a7299a1e..21ade8324fc 100644 --- a/packages/jobs/lib/execution/action.ts +++ b/packages/jobs/lib/execution/action.ts @@ -1,7 +1,7 @@ import { Err, Ok, metrics } from '@nangohq/utils'; import type { Result } from '@nangohq/utils'; import type { TaskAction } from '@nangohq/nango-orchestrator'; -import type { Config, NangoConnection, NangoProps } from '@nangohq/shared'; +import type { Config, NangoConnection } from '@nangohq/shared'; import { ErrorSourceEnum, LogActionEnum, @@ -15,7 +15,7 @@ import { getSyncConfigRaw } from '@nangohq/shared'; import { logContextGetter } from '@nangohq/logs'; -import type { DBEnvironment, DBSyncConfig, DBTeam } from '@nangohq/types'; +import type { DBEnvironment, DBSyncConfig, DBTeam, NangoProps } from '@nangohq/types'; import { startScript } from './operations/start.js'; import { bigQueryClient, slackService } from '../clients.js'; import { getRunnerFlags } from '../utils/flags.js'; diff --git a/packages/jobs/lib/execution/onEvent.ts b/packages/jobs/lib/execution/onEvent.ts index 3e8e9d5232a..e2ab91a4833 100644 --- a/packages/jobs/lib/execution/onEvent.ts +++ b/packages/jobs/lib/execution/onEvent.ts @@ -1,10 +1,10 @@ import { Err, metrics, Ok } from '@nangohq/utils'; import type { Result } from '@nangohq/utils'; import type { TaskOnEvent } from '@nangohq/nango-orchestrator'; -import type { Config, NangoConnection, NangoProps } from '@nangohq/shared'; +import type { Config, NangoConnection } from '@nangohq/shared'; import { configService, environmentService, featureFlags, getApiUrl, getEndUserByConnectionId, NangoError } from '@nangohq/shared'; import { logContextGetter } from '@nangohq/logs'; -import type { DBEnvironment, DBSyncConfig, DBTeam } from '@nangohq/types'; +import type { DBEnvironment, DBSyncConfig, DBTeam, NangoProps } from '@nangohq/types'; import { startScript } from './operations/start.js'; import { bigQueryClient } from '../clients.js'; import db from '@nangohq/database'; @@ -85,7 +85,7 @@ export async function startOnEvent(task: TaskOnEvent): Promise> { activityLogId: logCtx.id, secretKey: environment.secret_key, nangoConnectionId: task.connection.id, - syncConfig: syncConfig, + syncConfig, debug: false, runnerFlags: await getRunnerFlags(featureFlags), startedAt: new Date(), diff --git a/packages/jobs/lib/execution/operations/output.ts b/packages/jobs/lib/execution/operations/output.ts index ab0ef020f4f..0f6451d386e 100644 --- a/packages/jobs/lib/execution/operations/output.ts +++ b/packages/jobs/lib/execution/operations/output.ts @@ -2,12 +2,11 @@ import { orchestratorClient } from '../../clients.js'; import type { JsonValue } from 'type-fest'; import { logger } from '../../logger.js'; import { NangoError } from '@nangohq/shared'; -import type { NangoProps } from '@nangohq/shared'; import { handleSyncError, handleSyncSuccess } from '../sync.js'; import { handleActionError, handleActionSuccess } from '../action.js'; import { handleWebhookError, handleWebhookSuccess } from '../webhook.js'; import { handleOnEventError, handleOnEventSuccess } from '../onEvent.js'; -import type { ApiError, RunnerOutputError } from '@nangohq/types'; +import type { ApiError, NangoProps, RunnerOutputError } from '@nangohq/types'; import type { ClientError } from '@nangohq/nango-orchestrator'; import { toNangoError } from './utils/errors.js'; diff --git a/packages/jobs/lib/execution/operations/start.ts b/packages/jobs/lib/execution/operations/start.ts index e75232b4765..f1945d599f2 100644 --- a/packages/jobs/lib/execution/operations/start.ts +++ b/packages/jobs/lib/execution/operations/start.ts @@ -2,10 +2,10 @@ import type { Result } from '@nangohq/utils'; import { Err, Ok, integrationFilesAreRemote, isCloud, stringifyError } from '@nangohq/utils'; import tracer from 'dd-trace'; import type { LogContext } from '@nangohq/logs'; -import type { NangoProps } from '@nangohq/shared'; import { localFileService, remoteFileService } from '@nangohq/shared'; import { getRunner } from '../../runner/runner.js'; import type { JsonValue } from 'type-fest'; +import type { NangoProps } from '@nangohq/types'; export async function startScript({ taskId, diff --git a/packages/jobs/lib/execution/sync.ts b/packages/jobs/lib/execution/sync.ts index 6222bdddce7..534edaf9123 100644 --- a/packages/jobs/lib/execution/sync.ts +++ b/packages/jobs/lib/execution/sync.ts @@ -1,5 +1,5 @@ import tracer from 'dd-trace'; -import type { Config, Job, NangoProps } from '@nangohq/shared'; +import type { Config, Job } from '@nangohq/shared'; import { environmentService, externalWebhookService, @@ -26,7 +26,7 @@ import { } from '@nangohq/shared'; import { Err, Ok, metrics } from '@nangohq/utils'; import type { Result } from '@nangohq/utils'; -import type { DBEnvironment, DBSyncConfig, DBTeam, NangoConnection, SyncResult, SyncTypeLiteral } from '@nangohq/types'; +import type { DBEnvironment, DBSyncConfig, DBTeam, NangoConnection, NangoProps, SyncResult, SyncTypeLiteral } from '@nangohq/types'; import { sendSync as sendSyncWebhook } from '@nangohq/webhooks'; import { bigQueryClient, orchestratorClient, slackService } from '../clients.js'; import { startScript } from './operations/start.js'; diff --git a/packages/jobs/lib/execution/webhook.ts b/packages/jobs/lib/execution/webhook.ts index 0354b4cfb42..c2aa2410a61 100644 --- a/packages/jobs/lib/execution/webhook.ts +++ b/packages/jobs/lib/execution/webhook.ts @@ -2,7 +2,7 @@ import tracer from 'dd-trace'; import { Err, Ok, metrics } from '@nangohq/utils'; import type { Result } from '@nangohq/utils'; import type { TaskWebhook } from '@nangohq/nango-orchestrator'; -import type { Config, Job, NangoConnection, NangoProps, Sync } from '@nangohq/shared'; +import type { Config, Job, NangoConnection, Sync } from '@nangohq/shared'; import { NangoError, SyncStatus, @@ -20,7 +20,7 @@ import { } from '@nangohq/shared'; import { bigQueryClient } from '../clients.js'; import { logContextGetter } from '@nangohq/logs'; -import type { DBEnvironment, DBSyncConfig, DBTeam } from '@nangohq/types'; +import type { DBEnvironment, DBSyncConfig, DBTeam, NangoProps } from '@nangohq/types'; import { startScript } from './operations/start.js'; import { sendSync as sendSyncWebhook } from '@nangohq/webhooks'; import db from '@nangohq/database'; diff --git a/packages/jobs/lib/routes/tasks/putTask.ts b/packages/jobs/lib/routes/tasks/putTask.ts index 9937f20fd96..d6ad752e646 100644 --- a/packages/jobs/lib/routes/tasks/putTask.ts +++ b/packages/jobs/lib/routes/tasks/putTask.ts @@ -1,10 +1,9 @@ import { z } from 'zod'; -import type { ApiError, Endpoint } from '@nangohq/types'; +import type { ApiError, Endpoint, NangoProps } from '@nangohq/types'; import { validateRequest } from '@nangohq/utils'; import type { EndpointRequest, EndpointResponse, RouteHandler } from '@nangohq/utils'; import { handleError, handleSuccess } from '../../execution/operations/output.js'; import type { JsonValue } from 'type-fest'; -import type { NangoProps } from '@nangohq/shared'; const path = '/tasks/:taskId'; const method = 'PUT'; diff --git a/packages/jobs/package.json b/packages/jobs/package.json index d40be956f22..040d5493244 100644 --- a/packages/jobs/package.json +++ b/packages/jobs/package.json @@ -23,7 +23,6 @@ "@nangohq/nango-runner": "file:../runner", "@nangohq/shared": "file:../shared", "@nangohq/records": "file:../records", - "@nangohq/types": "file:../types", "@nangohq/utils": "file:../utils", "@nangohq/webhooks": "file:../webhooks", "@nangohq/fleet": "file:../fleet", @@ -37,6 +36,7 @@ "zod": "3.24.1" }, "devDependencies": { + "@nangohq/types": "file:../types", "@types/node": "^20.12.2", "nodemon": "3.1.9", "typescript": "5.7.3", diff --git a/packages/jobs/tsconfig.json b/packages/jobs/tsconfig.json index 8b8121484fb..df42e2f9db8 100644 --- a/packages/jobs/tsconfig.json +++ b/packages/jobs/tsconfig.json @@ -11,6 +11,9 @@ { "path": "../kvstore" }, + { + "path": "../orchestrator" + }, { "path": "../logs" }, @@ -23,6 +26,9 @@ { "path": "../runner" }, + { + "path": "../runner-sdk" + }, { "path": "../types" }, diff --git a/packages/node-client/lib/index.ts b/packages/node-client/lib/index.ts index dc7e9bdadef..9c7d692f636 100644 --- a/packages/node-client/lib/index.ts +++ b/packages/node-client/lib/index.ts @@ -232,7 +232,7 @@ export class Nango { /** * Updates an integration with the specified provider and configuration key * Only integrations using OAuth 1 & 2 can be updated, not integrations using API keys & Basic auth (because there is nothing to update for them) - * @param provider - The Nango API Configuration (cf. [providers.yaml](https://github.com/NangoHQ/nango/blob/master/packages/shared/providers.yaml)) + * @param provider - The Nango API Configuration (cf. [providers.yaml](https://github.com/NangoHQ/nango/blob/master/packages/providers/providers.yaml)) * @param providerConfigKey - The key identifying the provider configuration on Nango * @param credentials - Optional credentials to include, depending on the specific integration that you want to update * @returns A promise that resolves with the updated integration configuration object diff --git a/packages/providers/providers.yaml b/packages/providers/providers.yaml deleted file mode 120000 index d547ec4d2c0..00000000000 --- a/packages/providers/providers.yaml +++ /dev/null @@ -1 +0,0 @@ -../shared/providers.yaml \ No newline at end of file diff --git a/packages/providers/providers.yaml b/packages/providers/providers.yaml new file mode 100644 index 00000000000..415c2ed56a5 --- /dev/null +++ b/packages/providers/providers.yaml @@ -0,0 +1,7939 @@ +# yaml-language-server: $schema=./../../scripts/validation/providers/schema.json +accelo: + display_name: Accelo + categories: + - invoicing + - ticketing + auth_mode: OAUTH2 + authorization_url: https://${connectionConfig.subdomain}.api.accelo.com/oauth2/v0/authorize + token_url: https://${connectionConfig.subdomain}.api.accelo.com/oauth2/v0/token + scope_separator: ',' + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://${connectionConfig.subdomain}.api.accelo.com + docs: https://docs.nango.dev/integrations/all/accelo + connection_config: + subdomain: + type: string + title: Accelo Domain + description: The subdomain of your Accelo account + pattern: '^[a-z0-9_-]+$' + example: domain + suffix: .api.accelo.com + prefix: https:// + +acuity-scheduling: + display_name: Acuity Scheduling + categories: + - productivity + auth_mode: OAUTH2 + authorization_url: https://acuityscheduling.com/oauth2/authorize + token_url: https://acuityscheduling.com/oauth2/token + default_scopes: + - api-v1 + proxy: + base_url: https://acuityscheduling.com/api/v1 + docs: https://docs.nango.dev/integrations/all/acuity-scheduling + +adobe: + display_name: Adobe + categories: + - design + auth_mode: OAUTH2 + authorization_url: https://ims-na1.adobelogin.com/ims/authorize/v2 + token_url: https://ims-na1.adobelogin.com/ims/token/v3 + default_scopes: + - offline_access + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://ims-na1.adobelogin.com/ims + docs: https://docs.nango.dev/integrations/all/adobe + +adobe-umapi: + display_name: UMAPI (Adobe User Management API) + categories: + - other + auth_mode: OAUTH2_CC + token_url: https://ims-na1.adobelogin.com/ims/token/v2 + scope_separator: ',' + token_params: + grant_type: client_credentials + proxy: + headers: + x-api-key: ${connectionConfig.clientId} + retry: + after: 'retry-after' + base_url: https://usermanagement.adobe.io + docs: https://docs.nango.dev/integrations/all/adobe + post_connection_script: adobeUmapiPostConnection + docs_connect: https://docs.nango.dev/integrations/all/adobe-umapi/connect + connection_config: + clientId: + type: string + title: '' + description: '' + automated: true + +adyen: + display_name: Adyen + categories: + - payment + auth_mode: OAUTH2 + authorization_url: https://ca-${connectionConfig.environment}.adyen.com/ca/ca/oauth/connect.shtml + token_url: https://oauth-${connectionConfig.environment}.adyen.com/v1/token + scope_separator: ' ' + token_request_auth_method: basic + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://${connectionConfig.resource}-${connectionConfig.environment}.adyen.com + docs: https://docs.nango.dev/integrations/all/adyen + connection_config: + environment: + type: string + title: Environment + description: The environment to use + pattern: '^(live|test)$' + example: live|test + resource: + type: string + title: Resource + description: The resource to use for your various requests + pattern: '^[a-z0-9_-]+$' + example: kyc + suffix: -(live|test).adyen.com + prefix: https:// + +affinity: + display_name: Affinity + categories: + - crm + auth_mode: BASIC + proxy: + base_url: https://api.affinity.co + verification: + method: GET + endpoint: /lists + docs: https://docs.nango.dev/integrations/all/affinity + docs_connect: https://docs.nango.dev/integrations/all/affinity/connect + credentials: + username: + type: string + title: '' + description: '' + default_value: '' + hidden: true + password: + type: string + title: API Key + description: Your Affinity API Key + # https://api-docs.affinity.co/#introduction + # Affinity is using basic auth with an api key + doc_section: '#step-1-finding-your-api-key' + +aircall: + display_name: Aircall + categories: + - support + auth_mode: OAUTH2 + authorization_url: https://dashboard.aircall.io/oauth/authorize + token_url: https://api.aircall.io/v1/oauth/token + authorization_params: + response_type: code + scope: public_api + token_params: + grant_type: authorization_code + proxy: + base_url: https://api.aircall.io + retry: + at: 'x-aircallapi-reset' + paginate: + type: link + link_path_in_response_body: meta.next_page_link + response_path: results + docs: https://docs.nango.dev/integrations/all/aircall + +aircall-basic: + alias: aircall + display_name: Aircall (basic auth) + auth_mode: BASIC + proxy: + base_url: https://api.aircall.io + verification: + method: GET + endpoint: /v1/ping + paginate: + type: link + link_path_in_response_body: meta.next_page_link + response_path: results + docs_connect: https://docs.nango.dev/integrations/all/aircall-basic/connect + docs: https://docs.nango.dev/integrations/all/aircall + +airtable: + display_name: Airtable + categories: + - productivity + auth_mode: OAUTH2 + authorization_url: https://airtable.com/oauth2/v1/authorize + token_url: https://airtable.com/oauth2/v1/token + authorization_method: header + auth: + response_type: code + proxy: + base_url: https://api.airtable.com + webhook_routing_script: airtableWebhookRouting + docs: https://docs.nango.dev/integrations/all/airtable + +autodesk: + display_name: Autodesk + categories: + - design + auth_mode: OAUTH2 + authorization_url: https://developer.api.autodesk.com/authentication/v2/authorize + token_url: https://developer.api.autodesk.com/authentication/v2/token + scope_separator: ' ' + disable_pkce: true + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://developer.api.autodesk.com + retry: + after: 'retry-after' + docs: https://docs.nango.dev/integrations/all/autodesk + +algolia: + display_name: Algolia + categories: + - search + auth_mode: API_KEY + proxy: + base_url: https://${connectionConfig.APP_ID}.algolia.net + headers: + x-algolia-application-id: ${connectionConfig.APP_ID} + x-algolia-api-key: ${apiKey} + verification: + endpoint: /1/keys/${credentials.apiKey} + docs: https://docs.nango.dev/integrations/all/algolia + docs_connect: https://docs.nango.dev/integrations/all/algolia/connect + connection_config: + APP_ID: + type: string + title: Application ID + description: The application ID for your Algolia account + example: ERBSOWZO32 + pattern: '^[A-Z0-9]{10}$' + order: 1 + doc_section: '#step-1-finding-your-application-id' + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Algolia account + example: c5c28261f9ade4e34891ccf761491b94 + pattern: '^[a-zA-Z0-9]+$' + doc_section: '#step-2-finding-your-admin-api-key' + +amazon: + display_name: Amazon + categories: + - dev-tools + - e-commerce + auth_mode: OAUTH2 + authorization_url: https://www.amazon.com/ap/oa + token_url: https://api.amazon.${connectionConfig.extension}/auth/o2/token + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://api.amazon.com + docs: https://docs.nango.dev/integrations/all/amazon + connection_config: + extension: + type: string + title: Domain Extension + description: The domain extension for your Amazon account + example: com + pattern: '^[a-z.]+$' + +anrok: + display_name: Anrok + categories: + - legal + auth_mode: API_KEY + proxy: + base_url: https://api.anrok.com + headers: + authorization: Bearer ${apiKey} + retry: + after: 'retry-after' + docs: https://docs.nango.dev/integrations/all/anrok + docs_connect: https://docs.nango.dev/integrations/all/anrok/connect + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Anrok account + doc_section: '#step-1-finding-your-api-key' + +amplitude: + display_name: Amplitude (Event Streaming API) + categories: + - analytics + auth_mode: BASIC + proxy: + base_url: https://amplitude.com + verification: + method: GET + endpoint: /api/2/events/list + docs: https://docs.nango.dev/integrations/all/amplitude + credentials: + username: + type: string + title: API Key + description: Your Amplitude API Key + password: + type: string + title: Secret Key + description: Your Amplitude secret key + # https://amplitude.com/docs/apis/authentication + # Amplitude is using basic auth with an api key + +anthropic: + display_name: Anthropic + categories: + - productivity + - dev-tools + auth_mode: API_KEY + proxy: + base_url: https://api.anthropic.com + headers: + x-api-key: ${apiKey} + anthropic-version: ${connectionConfig.version} + content-type: application/json + retry: + after: 'retry-after' + docs: https://docs.nango.dev/integrations/all/anthropic + connection_config: + version: + type: string + title: API Version + description: The version of the Anthropic API to use + pattern: '^[0-9]{4}-[0-9]{2}-[0-9]{2}$' + example: '2023-06-01' + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Anthropic account + +apaleo: + display_name: Apaleo + categories: + - erp + auth_mode: OAUTH2 + authorization_url: https://identity.apaleo.com/connect/authorize + token_url: https://identity.apaleo.com/connect/token + scope_separator: ' ' + token_params: + grant_type: authorization_code + authorization_params: + response_type: code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://api.apaleo.com + headers: + content-type: application/json + retry: + after: 'retry-after' + docs: https://docs.nango.dev/integrations/all/apaleo + +apollo: + display_name: Apollo + categories: + - marketing + auth_mode: API_KEY + proxy: + base_url: https://app.apollo.io/api + verification: + method: GET + endpoint: /v1/contact_stages + query: + api_key: ${apiKey} + docs: https://docs.nango.dev/integrations/all/apollo + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Apollo account + +apollo-oauth: + display_name: Apollo (OAuth) + categories: + - marketing + auth_mode: OAUTH2 + authorization_url: https://app.apollo.io + token_url: https://app.apollo.io/api/v1/oauth/token + authorization_url_fragment: oauth/authorize + body_format: json + disable_pkce: true + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://app.apollo.io/api + docs: https://docs.nango.dev/integrations/all/apollo + +apple-app-store: + display_name: Apple App Store + auth_mode: APP_STORE + token_url: https://api.appstoreconnect.apple.com/v1/apps + authorization_params: + audience: appstoreconnect-v1 + proxy: + base_url: https://api.appstoreconnect.apple.com + docs: https://docs.nango.dev/integrations/all/apple-app-store + +asana: + display_name: Asana + categories: + - productivity + - ticketing + auth_mode: OAUTH2 + authorization_url: https://app.asana.com/-/oauth_authorize + token_url: https://app.asana.com/-/oauth_token + token_params: + grant_type: authorization_code + auth: + response_type: code + default_scopes: + - default + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://app.asana.com + retry: + after: 'retry-after' + paginate: + type: cursor + cursor_path_in_response: next_page.offset + cursor_name_in_request: offset + response_path: data + limit_name_in_request: limit + docs: https://docs.nango.dev/integrations/all/asana + +asana-scim: + display_name: Asana (SCIM API) + categories: + - productivity + - ticketing + auth_mode: API_KEY + proxy: + base_url: https://app.asana.com/api + verification: + method: GET + endpoint: /1.0/scim/Users + headers: + authorization: Bearer ${apiKey} + docs: https://docs.nango.dev/integrations/all/asana + docs_connect: https://docs.nango.dev/integrations/all/asana-scim/connect + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Asana scim account + doc_section: '#step-1-finding-asana-api-key' + +ashby: + display_name: Ashby + categories: + - ats + auth_mode: BASIC + proxy: + base_url: https://api.ashbyhq.com + verification: + method: POST + endpoint: apiKey.info + docs: https://docs.nango.dev/integrations/all/ashby + credentials: + username: + type: string + title: API Key + description: The API Key of your Ashby account + password: + type: string + title: '' + description: '' + default_value: '' + hidden: true + +atlas-so: + display_name: Atlas.so + categories: + - support + auth_mode: API_KEY + proxy: + headers: + authorization: Bearer ${apiKey} + base_url: https://api.atlas.so/v1 + docs: https://docs.nango.dev/integrations/all/atlas-so + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Atlas.so account + +atlassian: + display_name: Atlassian + categories: + - dev-tools + auth_mode: OAUTH2 + authorization_url: https://auth.atlassian.com/authorize + token_url: https://auth.atlassian.com/oauth/token + default_scopes: + - offline_access + authorization_params: + response_type: code + audience: api.atlassian.com + prompt: consent + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://api.atlassian.com + docs: https://docs.nango.dev/integrations/all/atlassian + +attio: + display_name: Attio + categories: + - crm + auth_mode: OAUTH2 + authorization_url: https://app.attio.com/authorize + token_url: https://app.attio.com/oauth/token + token_params: + grant_type: authorization_code + auth: + response_type: code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://app.attio.com + docs: https://docs.nango.dev/integrations/all/attio + +auth0: + display_name: Auth0 + auth_mode: OAUTH2 + authorization_url: https://${connectionConfig.subdomain}.auth0.com/authorize + token_url: https://${connectionConfig.subdomain}.auth0.com/oauth/token + authorization_params: + response_type: code + response_mode: query + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + docs: https://docs.nango.dev/integrations/all/auth0 + proxy: + base_url: https://${connectionConfig.subdomain}.auth0.com + connection_config: + subdomain: + type: string + title: Auth0 Domain + description: The subdomain of your Auth0 account + pattern: '^[a-z0-9_-]+$' + example: domain + suffix: .auth0.com + prefix: https:// + +avalara: + display_name: Avalara + categories: + - legal + auth_mode: BASIC + proxy: + headers: + x-avalara-client: ${connectionConfig.avalaraClient} + content-type: application/json + base_url: https://rest.avatax.com/api/v2 + verification: + method: GET + endpoint: /utilities/subscriptions + docs: https://docs.nango.dev/integrations/all/avalara + docs_connect: https://docs.nango.dev/integrations/all/avalara/connect + credentials: + username: + type: string + title: User Name / Account ID + description: Avalara User Name / Account ID + doc_section: '#step-1-finding-your-pair-keys' + password: + type: string + title: Avalara Password / License Key + description: Your Password / License Key + # https://developer.avalara.com/avatax/authentication-in-rest/ + # Avalara is using basic auth with combination of (username and password) + # or (Account ID and License Key) + doc_section: '#step-1-finding-your-pair-keys' + connection_config: + avalaraClient: + type: string + title: Avalara Client + description: The Avalara client for your Avalara account + pattern: '^[a-zA-Z0-9_-]+$' + doc_section: '#step-2-generating-an-avalara-client' + +avalara-sandbox: + display_name: Avalara (sandbox) + categories: + - legal + auth_mode: BASIC + proxy: + headers: + x-avalara-client: ${connectionConfig.avalaraClient} + content-type: application/json + base_url: https://sandbox-rest.avatax.com/api/v2 + verification: + method: GET + endpoint: /utilities/subscriptions + docs: https://docs.nango.dev/integrations/all/avalara + docs_connect: https://docs.nango.dev/integrations/all/avalara-sandbox/connect + credentials: + username: + type: string + title: User Name / Account ID + description: Avalara User Name / Account ID + doc_section: '#step-1-finding-your-pair-keys' + password: + type: string + title: Password / License Key + description: Avalara Password / License Key + # https://developer.avalara.com/avatax/authentication-in-rest/ + # Avalara is using basic auth with combination of (username and password) + # or (Account ID and License Key) + doc_section: '#step-1-finding-your-pair-keys' + connection_config: + avalaraClient: + type: string + title: Avalara Client + description: The Avalara client for your Avalara account + pattern: '^[a-zA-Z0-9_-]+$' + doc_section: '#step-2-generating-an-avalara-client' + +aws: + display_name: AWS + categories: + - dev-tools + - e-commerce + auth_mode: OAUTH2 + authorization_url: https://${connectionConfig.subdomain}.auth.${connectionConfig.extension}.amazoncognito.com/oauth2/authorize + token_url: https://${connectionConfig.subdomain}.auth.${connectionConfig.extension}.amazoncognito.com/oauth2/token + token_params: + grant_type: authorization_code + auth: + response_type: code + refresh_params: + grant_type: refresh_token + default_scopes: + - openid + proxy: + base_url: https://cognito-${apiSubdomain}.amazonaws.com + docs: https://docs.nango.dev/integrations/all/aws + connection_config: + subdomain: + type: string + title: AWS Domain + description: The subdomain of your AWS account + pattern: '^[a-z0-9_-]+$' + example: domain + suffix: .amazoncognito.com + prefix: https:// + extension: + type: string + title: Domain Extension + description: The domain extension of your AWS account + example: com + pattern: '^[a-z.]+$' + apiSubdomain: + type: string + title: API Subdomain + description: The API subdomain to the API you want to connect to + example: idp.us-east-2 + pattern: '^[a-z.-]+$' + suffix: .amazonaws.com + prefix: https://cognito- + +aws-iam: + display_name: AWS IAM + categories: + - dev-tools + auth_mode: BASIC + proxy: + base_url: https://iam.amazonaws.com + verification: + method: GET + endpoint: /?Action=ListUsers + connection_config: + region: ${connectionConfig.region} + retry: + at: 'x-ratelimit-reset' + docs: https://docs.nango.dev/integrations/all/aws + docs_connect: https://docs.nango.dev/integrations/all/aws-iam/connect + credentials: + username: + type: string + title: AWS Access Key ID + description: Your Access Key ID + doc_section: '#step-1-finding-your-pair-keys' + password: + type: string + title: AWS Secret Access Key + description: Your Secret Access Key + # https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_sigv.html + # aws-iam is using basic auth with AWS Access Key ID and Secret Access Key + doc_section: '#step-1-finding-your-pair-keys' + connection_config: + region: + type: string + title: Region + description: The region to where your AWS account is hosted + example: us-east-1 + pattern: '^[a-z0-9-]+$' + doc_section: '#step-2-finding-your-region-host' + +bamboohr: + display_name: BambooHR + categories: + - hr + auth_mode: OAUTH2 + authorization_url: https://${connectionConfig.subdomain}.bamboohr.com/authorize.php + token_url: https://${connectionConfig.subdomain}.bamboohr.com/token.php + authorization_params: + response_type: code + request: authorize + token_params: + grant_type: authorization_code + request: token + proxy: + base_url: https://api.bamboohr.com/api/gateway.php/${connectionConfig.subdomain} + docs: https://docs.nango.dev/integrations/all/bamboohr + connection_config: + subdomain: + type: string + title: BambooHR Domain + description: The subdomain of your BambooHR account + pattern: '^[a-z0-9_-]+$' + example: domain + suffix: .bamboohr.com + prefix: https:// + order: 1 + +bamboohr-basic: + display_name: BambooHR (basic auth) + categories: + - hr + auth_mode: BASIC + proxy: + base_url: https://api.bamboohr.com/api/gateway.php/${connectionConfig.subdomain} + verification: + method: GET + endpoint: /v1/meta/fields + docs: https://docs.nango.dev/integrations/all/bamboohr + docs_connect: https://docs.nango.dev/integrations/all/bamboohr-basic/connect + connection_config: + subdomain: + type: string + title: BambooHR Domain + description: The subdomain of your BambooHR account + pattern: '^[a-z0-9_-]+$' + example: domain + suffix: .bamboohr.com + prefix: https:// + order: 1 + doc_section: '#step-1-finding-your-subdomain' + credentials: + username: + type: string + title: API key + description: The API Key of your BambooHR account + pattern: '^[a-zA-Z0-9]+$' + secret: true + doc_section: '#step-2-finding-your-api-key' + password: + type: string + title: Password + description: Password + # https://documentation.bamboohr.com/docs/getting-started + # Bamboo HR is using basic auth with an api key + default_value: x + hidden: true + +battlenet: + display_name: Battle.net + categories: + - gaming + auth_mode: OAUTH2 + authorization_url: https://oauth.battle.${connectionConfig.extension}/authorize + token_url: https://oauth.battle.${connectionConfig.extension}/token + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + proxy: + base_url: https://${connectionConfig.apiDomain} + docs: https://docs.nango.dev/integrations/all/battlenet + connection_config: + extension: + type: string + title: Domain Extension + description: The domain extension of your Battle.net account + example: com + pattern: '^[a-z.]+$' + order: 1 + apiDomain: + type: string + title: API Domain + description: The domain to where you will access your API + example: us.api.blizzard.com + pattern: '^[a-z.]+$' + prefix: https:// + +beehiiv: + display_name: Beehiiv + categories: + - communication + - marketing + auth_mode: API_KEY + proxy: + headers: + authorization: Bearer ${apiKey} + base_url: https://api.beehiiv.com/v2/publications/${connectionConfig.publicationId} + verification: + method: GET + endpoint: /posts + docs: https://docs.nango.dev/integrations/all/beehiiv + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Beehiiv account + example: 8ab3sjxqvHzyUnP9JhvlfT6C0wsbgr5XQrpaZZjxJkYBPy6sntvT1M2Lk94VQeRb + pattern: '^[a-zA-Z0-9]{64}$' + connection_config: + publicationId: + type: string + title: Publication Id + description: The prefixed ID of the publication object + example: pub_a3d1b49e-2a5d-4f4b-97c8-8f32e1d2f7b9 + pattern: '^(pub_[0-9a-fA-F\-]+)$' + +bigcommerce: + display_name: BigCommerce + categories: + - e-commerce + auth_mode: OAUTH2 + authorization_url: https://login.bigcommerce.com/oauth2/authorize + token_url: https://login.bigcommerce.com/oauth2/token + scope_separator: ' ' + authorization_params: + response_type: code + context: stores/${connectionConfig.storeHash} + account_uuid: ${connectionConfig.accountUuid} + token_params: + context: stores/${connectionConfig.storeHash} + grant_type: authorization_code + proxy: + base_url: https://api.bigcommerce.com/stores/${connectionConfig.storeHash} + docs: https://docs.nango.dev/integrations/all/bigcommerce + connection_config: + storeHash: + type: string + title: Store Hash + description: The store hash of your BigCommerce account + pattern: '^[a-zA-Z0-9]+$' + accountUuid: + type: string + title: Account UUID + description: The account UUID of your BigCommerce account + format: uuid + example: 123e4567-e89b-12d3-a456-426614174000 + +bill-sandbox: + display_name: Bill (Connect API sandbox) + categories: + - payment + auth_mode: BILL + token_url: https://gateway.stage.bill.com/connect/v3/login + proxy: + base_url: https://gateway.stage.bill.com/connect + docs: https://docs.nango.dev/integrations/all/bill + docs_connect: https://docs.nango.dev/integrations/all/bill-sandbox/connect + +bill: + display_name: Bill (Connect API) + categories: + - payment + auth_mode: BILL + token_url: https://gateway.prod.bill.com/connect/v3/login + proxy: + base_url: https://gateway.prod.bill.com/connect + docs: https://docs.nango.dev/integrations/all/bill + +bitbucket: + display_name: Bitbucket + categories: + - dev-tools + auth_mode: OAUTH2 + authorization_url: https://bitbucket.org/site/oauth2/authorize + token_url: https://bitbucket.org/site/oauth2/access_token + proxy: + base_url: https://api.bitbucket.org + docs: https://docs.nango.dev/integrations/all/bitbucket + +bitdefender: + display_name: Bitdefender + categories: + - other + auth_mode: BASIC + proxy: + base_url: ${connectionConfig.ACCESS_URL} + retry: + after: 'retry-after' + docs: https://docs.nango.dev/integrations/all/bitdefender + docs_connect: https://docs.nango.dev/integrations/all/bitdefender/connect + credentials: + username: + type: string + title: API Key + description: The API Key of your Bitdefender account + doc_section: '#step-1-finding-your-api-key' + password: + type: string + title: '' + description: '' + default_value: '' + hidden: true + connection_config: + ACCESS_URL: + type: string + title: Access URL + description: The access URL of your Bitdefender account + example: https://api.bitdefender.com + format: uri + pattern: '^https://.*' + doc_section: '#step-1-finding-your-api-key' + +bitly: + display_name: Bitly + categories: + - marketing + - social + auth_mode: OAUTH2 + authorization_url: https://bitly.com/oauth/authorize + token_url: https://api-ssl.bitly.com/oauth/access_token + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + proxy: + base_url: https://api-ssl.bitly.com + docs: https://docs.nango.dev/integrations/all/bitly + +blackbaud: + display_name: Blackbaud + categories: + - crm + auth_mode: OAUTH2 + authorization_url: https://app.blackbaud.com/oauth/authorize + token_url: https://oauth2.sky.blackbaud.com/token + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://api.sky.blackbaud.com + docs: https://docs.nango.dev/integrations/all/blackbaud + +blandai: + display_name: BlandAI + categories: + - support + auth_mode: API_KEY + proxy: + base_url: https://api.bland.ai + headers: + authorization: ${apiKey} + docs: https://docs.nango.dev/integrations/all/blandai + credentials: + apiKey: + type: string + title: API Key + description: The API key for your BlandAI account + +boldsign: + display_name: BoldSign + categories: + - legal + auth_mode: OAUTH2 + authorization_url: https://account.boldsign.com/connect/authorize + token_url: https://account.boldsign.com/connect/token + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://api.boldsign.com + docs: https://docs.nango.dev/integrations/all/boldsign + +box: + display_name: Box + categories: + - knowledge-base + - storage + auth_mode: OAUTH2 + authorization_url: https://account.box.com/api/oauth2/authorize + token_url: https://api.box.com/oauth2/token + proxy: + base_url: https://api.box.com + docs: https://docs.nango.dev/integrations/all/box + +booking-com: + display_name: Booking.com + categories: + - e-commerce + auth_mode: BASIC + proxy: + base_url: https://${connectionConfig.environmentType}-xml.booking.com + docs: https://docs.nango.dev/integrations/all/booking-com + connection_config: + environmentType: + type: string + title: Environment Type + description: The environment type for your various requests + pattern: '^(secure-supply|supply)$' + example: secure-supply|supply + suffix: -xml.booking.com + prefix: https:// + +braintree: + display_name: Braintree + categories: + - payment + auth_mode: OAUTH2 + authorization_url: https://api.braintreegateway.com/oauth/connect + token_url: https://api.braintreegateway.com/oauth/access_tokens + scope_separator: ',' + authorization_method: header + body_format: json + token_params: + grant_type: authorization_code + redirect_uri_metadata: + - merchantId + proxy: + base_url: https://api.braintreegateway.com + docs: https://docs.nango.dev/integrations/all/braintree + +braintree-sandbox: + display_name: Braintree (sandbox) + auth_mode: OAUTH2 + authorization_url: https://api.sandbox.braintreegateway.com/oauth/connect + token_url: https://api.sandbox.braintreegateway.com/oauth/access_tokens + scope_separator: ',' + authorization_method: header + body_format: json + token_params: + grant_type: authorization_code + redirect_uri_metadata: + - merchantId + proxy: + base_url: https://api.sandbox.braintreegateway.com + docs: https://docs.nango.dev/integrations/all/braintree + +braze: + display_name: Braze + categories: + - communication + auth_mode: API_KEY + proxy: + base_url: https://rest.${connectionConfig.instanceUrl} + headers: + authorization: Bearer ${apiKey} + retry: + at: 'x-ratelimit-reset' + docs: https://docs.nango.dev/integrations/all/braze + docs_connect: https://docs.nango.dev/integrations/all/braze/connect + connection_config: + instanceUrl: + type: string + title: Instance URL + description: The REST API URL of your Braze instance + example: iad-02.braze.com + format: hostname + prefix: https://rest. + order: 1 + doc_section: '#step-1-finding-your-instance-url' + credentials: + apiKey: + type: string + title: API Key + description: The API key to your Braze account + doc_section: '#step-2-finding-your-api-key' + +brevo-api-key: + display_name: Brevo (api key) + categories: + - marketing + auth_mode: API_KEY + proxy: + headers: + api-key: ${apiKey} + base_url: https://api.brevo.com/v3 + docs: https://docs.nango.dev/integrations/all/brevo + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Brevo account + +brex: + display_name: Brex + categories: + - banking + auth_mode: OAUTH2 + authorization_url: https://accounts-api.brex.com/oauth2/default/v1/authorize + token_url: https://accounts-api.brex.com/oauth2/default/v1/token + default_scopes: + - openid + - offline_access + proxy: + base_url: https://platform.brexapis.com + docs: https://docs.nango.dev/integrations/all/brex + +brex-api-key: + display_name: Brex (api key) + auth_mode: API_KEY + proxy: + headers: + authorization: Bearer ${apiKey} + base_url: https://platform.brexapis.com + docs: https://docs.nango.dev/integrations/all/brex + docs_connect: https://docs.nango.dev/integrations/all/brex-api-key/connect + credentials: + apiKey: + type: string + title: API Token + description: The API Token to your Brex account + example: bxt_vRUwQT3snBmA1IDVq5iK1kXc4N0bhxr377z4 + pattern: '^bxt_[a-zA-Z0-9]+$' + doc_section: '#step-1-finding-your-api-token' + +brex-staging: + display_name: Brex (staging) + auth_mode: OAUTH2 + authorization_url: https://accounts-api.staging.brexapps.com/oauth2/default/v1/authorize + token_url: https://accounts-api.staging.brexapps.com/oauth2/default/v1/token + proxy: + base_url: https://platform.staging.brexapis.com + docs: https://docs.nango.dev/integrations/all/brex + +brightcrowd: + display_name: BrightCrowd + categories: + - social + auth_mode: OAUTH2_CC + token_url: https://bcb-staging.auth.us-east-1.amazoncognito.com/oauth2/token + token_request_auth_method: basic + token_params: + grant_type: client_credentials + proxy: + base_url: https://api.brightcrowd.com/partner + paginate: + type: cursor + cursor_path_in_response: nextPageToken + cursor_name_in_request: pageToken + docs: https://docs.nango.dev/integrations/all/brightcrowd + docs_connect: https://docs.nango.dev/integrations/all/brightcrowd/connect + +builder-io-private: + display_name: Builder.io (private) + categories: + - dev-tools + - design + - cms + auth_mode: API_KEY + proxy: + base_url: https://${connectionConfig.domain} + headers: + authorization: Bearer ${apiKey} + docs: https://docs.nango.dev/integrations/all/builder-io + docs_connect: https://docs.nango.dev/integrations/all/builder-io-private/connect + connection_config: + domain: + type: string + title: Domain + description: The domain used to access your Builder.io API + example: cdn.builder.io + format: hostname + prefix: https:// + doc_section: '#step-1-finding-your-api-domain' + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Builder.io account + pattern: '^[a-zA-Z0-9]+$' + example: bb209fb71eh2412dbe0114bdae18fd15 + doc_section: '#step-2-finding-your-api-key' + +builder-io-public: + display_name: Builder.io (public) + categories: + - dev-tools + - design + - cms + auth_mode: API_KEY + proxy: + base_url: https://${connectionConfig.domain} + query: + apiKey: ${apiKey} + docs: https://docs.nango.dev/integrations/all/builder-io + docs_connect: https://docs.nango.dev/integrations/all/builder-io-public/connect + connection_config: + domain: + type: string + title: Domain + description: The domain used to access your Builder.io API + example: builder.io + format: hostname + prefix: https:// + doc_section: '#step-1-finding-your-api-domain' + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Builder.io account + pattern: '^[a-zA-Z0-9]+$' + example: bb209fb71eh2412dbe0114bdae18fd15 + doc_section: '#step-2-finding-your-api-key' + +buildium: + display_name: Buildium + categories: + - accounting + - crm + - payment + auth_mode: API_KEY + proxy: + base_url: https://api.buildium.com + headers: + x-buildium-client-id: ${connectionConfig.clientId} + x-buildium-client-secret: ${apiKey} + verification: + method: GET + endpoint: /v1/rentals + docs: https://docs.nango.dev/integrations/all/buildium + docs_connect: https://docs.nango.dev/integrations/all/buildium/connect + connection_config: + clientId: + type: string + title: Client ID + description: Your API Key Client ID + pattern: '^[a-f0-9-]+$' + example: a228f0e7-b4a3-4150-b9ae-8552fc2880d3 + doc_section: '#step-2-finding-your-client-id-and-secret' + order: 1 + credentials: + apiKey: + type: string + title: Secret + description: The Secret for your Buildium account + pattern: '^[A-Za-z0-9+/]+$' + example: uOq2p+xlgpFdijfV/HqY+EvYpZKHRwlyhGuAVbJIxXs + doc_section: '#step-2-finding-your-client-id-and-secret' + +builtwith: + display_name: BuiltWith + categories: + - dev-tools + - analytics + - crm + - marketing + - e-commerce + auth_mode: API_KEY + proxy: + base_url: https://api.builtwith.com + query: + KEY: ${apiKey} + docs: https://docs.nango.dev/integrations/all/builtwith + docs_connect: https://docs.nango.dev/integrations/all/builtwith/connect + credentials: + apiKey: + type: string + title: API Key + description: The API key for your BuiltWith account + example: 1bc32cba-a5d6-438a-bbcc-af312f560a3c + format: uuid + doc_section: '#step-1-finding-your-api-key' + +cal-com-v1: + display_name: Cal.com (v1) + categories: + - productivity + auth_mode: API_KEY + proxy: + base_url: https://api.cal.com/v1 + query: + apiKey: ${apiKey} + retry: + at: 'x-ratelimit-reset' + verification: + method: GET + endpoint: /me + docs: https://docs.nango.dev/integrations/all/cal-com + docs_connect: https://docs.nango.dev/integrations/all/cal-com-v1/connect + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Cal.com account + pattern: '^cal_[a-zA-Z0-9_]+$' + example: cal_xxxxxx + doc_section: '#step-1-finding-your-api-key' +cal-com-v2: + display_name: Cal.com (v2) + categories: + - productivity + auth_mode: API_KEY + proxy: + base_url: https://api.cal.com/v2 + headers: + authorization: Bearer ${apiKey} + paginate: + type: cursor + cursor_name_in_request: cursor + cursor_path_in_response: data.data.nextCursor + limit_name_in_request: limit + retry: + at: 'x-ratelimit-reset' + verification: + method: GET + endpoint: /me + docs: https://docs.nango.dev/integrations/all/cal-com + docs_connect: https://docs.nango.dev/integrations/all/cal-com-v2/connect + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Cal.com account + pattern: '^cal_[a-zA-Z0-9_]+$' + example: cal_xxxxxx + doc_section: '#step-1-finding-your-api-key' + +calendly: + display_name: Calendly + categories: + - productivity + auth_mode: OAUTH2 + authorization_url: https://auth.calendly.com/oauth/authorize + token_url: https://auth.calendly.com/oauth/token + authorization_params: + response_type: code + proxy: + base_url: https://api.calendly.com + paginate: + type: link + link_path_in_response_body: pagination.next_page + retry: + at: 'x-ratelimit-reset' + token_response_metadata: + - owner + post_connection_script: calendlyPostConnection + docs: https://docs.nango.dev/integrations/all/calendly + +canny: + display_name: Canny + categories: + - support + auth_mode: API_KEY + proxy: + base_url: https://canny.io/api/v1 + query: + apiKey: ${apiKey} + verification: + method: POST + endpoint: /boards/list + docs: https://docs.nango.dev/integrations/all/canny + docs_connect: https://docs.nango.dev/integrations/all/canny/connect + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Canny account + example: a1f5937c-82df-bd29-4e3a-7b6fda8c54d1 + pattern: '^[a-zA-Z0-9-]+$' + doc_section: '#step-1-finding-your-api-key' +canva-scim: + display_name: Canva (SCIM API) + categories: + - design + - dev-tools + auth_mode: API_KEY + proxy: + base_url: https://www.canva.com/_scim + headers: + authorization: Bearer ${apiKey} + accept: application/json + content-type: application/json + docs: https://docs.nango.dev/integrations/all/canva + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Canva scim account + doc_section: '#step-1-finding-canva-api-key' + +certn: + display_name: Certn + categories: + - legal + auth_mode: API_KEY + proxy: + base_url: https://api.certn.co + headers: + authorization: Bearer ${apiKey} + paginate: + type: link + link_path_in_response_body: next + response_path: results + verification: + method: GET + endpoint: /api/v2/teams + docs: https://docs.nango.dev/integrations/all/certn + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Certn account + +certn-partner: + display_name: Certn Partner + categories: + - legal + auth_mode: OAUTH2_CC + proxy: + headers: + authorization: Bearer ${apiKey} + base_url: https://api.certn.co + paginate: + type: offset + offset_name_in_request: page + response_path: data + limit_name_in_request: limit + verification: + method: GET + endpoint: /api/v2/teams + docs: https://docs.nango.dev/integrations/all/certn + +chargebee: + display_name: Chargebee + categories: + - payment + auth_mode: BASIC + proxy: + base_url: https://${connectionConfig.subdomain}.chargebee.com + verification: + method: GET + endpoint: /api/v2/business_entities + retry: + after: 'retry-after' + docs: https://docs.nango.dev/integrations/all/chargebee + connection_config: + subdomain: + type: string + title: Chargebee Domain + description: The subdomain of your Chargebee account + pattern: '^[a-z0-9_-]+$' + example: domain + suffix: .chargebee.com + prefix: https:// + +chattermill: + display_name: Chattermill + categories: + - support + - analytics + auth_mode: API_KEY + proxy: + base_url: https://${connectionConfig.subdomain}.chattermill.com + headers: + authorization: Bearer ${apiKey} + accept: application/json + content-type: application/json + docs: https://docs.nango.dev/integrations/all/chattermill + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Chattermill account + connection_config: + subdomain: + type: string + title: Chattermill subdomain + description: The subdomain for your api requests + pattern: '^(app|api|backend)$' + example: 'app|api|backend' + suffix: .chattermill.com + prefix: https:// + +checkr-partner: + display_name: Checkr Partner + categories: + - legal + auth_mode: OAUTH2 + authorization_url: https://partners.checkr.com/authorize/${connectionConfig.client_id} + token_url: https://api.checkr.com/oauth/tokens + disable_pkce: true + token_params: + grant_type: authorization_code + proxy: + retry: + at: 'x-ratelimit-reset' + base_url: https://api.checkr.com + token_response_metadata: + - checkr_account_id + webhook_routing_script: checkrWebhookRouting + post_connection_script: checkrPostConnection + docs: https://docs.nango.dev/integrations/all/checkr-partner + connection_config: + client_id: + type: string + title: Client ID + description: The client ID of your Checkr Partner account + +checkr-partner-staging: + display_name: Checkr Partner (staging) + categories: + - legal + auth_mode: OAUTH2 + authorization_url: https://partners.checkrhq-staging.net/authorize/${connectionConfig.client_id} + token_url: https://api.checkr-staging.com/oauth/tokens + disable_pkce: true + token_params: + grant_type: authorization_code + proxy: + retry: + at: 'x-ratelimit-reset' + base_url: https://api.checkr-staging.com + token_response_metadata: + - checkr_account_id + webhook_routing_script: checkrWebhookRouting + post_connection_script: checkrPostConnection + docs: https://docs.nango.dev/integrations/all/checkr-partner + connection_config: + client_id: + type: string + title: Client ID + description: The client ID of your Checkr Partner account + +checkout-com: + display_name: Checkout.com + categories: + - payment + auth_mode: OAUTH2_CC + token_url: https://access.checkout.com/connect/token + token_request_auth_method: basic + token_params: + grant_type: client_credentials + proxy: + headers: + content-type: application/json + accept: application/json + base_url: https://api.checkout.com + docs: https://docs.nango.dev/integrations/all/checkout-com + +checkout-com-sandbox: + display_name: Checkout.com (sandbox) + categories: + - payment + auth_mode: OAUTH2_CC + token_url: https://access.sandbox.checkout.com/connect/token + token_request_auth_method: basic + token_params: + grant_type: client_credentials + proxy: + headers: + content-type: application/json + accept: application/json + base_url: https://api.sandbox.checkout.com + docs: https://docs.nango.dev/integrations/all/checkout-com + +chorus: + display_name: Chorus + auth_mode: API_KEY + proxy: + base_url: https://chorus.ai + verification: + method: GET + endpoint: /api/v1/users/me + headers: + authorization: Bearer ${apiKey} + docs: https://docs.nango.dev/integrations/all/chorus + docs_connect: https://docs.nango.dev/integrations/all/chorus/connect + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Chorus account + doc_section: '#step-1-generating-your-chorus-api-key' + +circle-so: + display_name: Circle.so + categories: + - communication + auth_mode: API_KEY + proxy: + base_url: https://app.circle.so + headers: + authorization: Token ${apiKey} + docs: https://docs.nango.dev/integrations/all/circle-so + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Circle.so account + +clari-copilot: + display_name: Clari Copilot + categories: + - marketing + auth_mode: API_KEY + proxy: + headers: + x-api-key: ${apiKey} + x-api-password: ${connectionConfig.API_PASSWORD} + base_url: https://rest-api.copilot.clari.com + docs: https://docs.nango.dev/integrations/all/clari-copilot + connection_config: + API_PASSWORD: + type: string + title: API Password + description: The API password of your Clari Copilot account + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Clari Copilot account + +clickup: + display_name: ClickUp + categories: + - productivity + - ticketing + auth_mode: OAUTH2 + authorization_url: https://app.clickup.com/api + token_url: https://api.clickup.com/api/v2/oauth/token + proxy: + base_url: https://api.clickup.com + docs: https://docs.nango.dev/integrations/all/clickup + +cloudentity: + display_name: Cloudentity + auth_mode: OAUTH2_CC + categories: + - other + token_url: https://${connectionConfig.tenantID}.${connectionConfig.regionID}.authz.cloudentity.io/${connectionConfig.tenantID}/${connectionConfig.workspaceID}/oauth2/token + scope_separator: ' ' + token_params: + grant_type: client_credentials + proxy: + base_url: https://${connectionConfig.tenantID}.${connectionConfig.regionID}.authz.cloudentity.io/${connectionConfig.tenantID}/${connectionConfig.workspaceID} + docs: https://docs.nango.dev/integrations/all/cloudentity + connection_config: + tenantID: + type: string + title: Tenant ID + description: The tenant ID of your Cloudentity account + regionID: + type: string + title: Region ID + description: The region ID of your Cloudentity account + workspaceID: + type: string + title: Workspace ID + description: The workspace ID of your Cloudentity account + +close: + display_name: Close + categories: + - crm + auth_mode: OAUTH2 + authorization_url: https://app.close.com/oauth2/authorize + token_url: https://api.close.com/oauth2/token/ + authorization_params: + response_type: code + default_scopes: + - offline_access + proxy: + base_url: https://api.close.com/api + docs: https://docs.nango.dev/integrations/all/close + +coda: + display_name: Coda + categories: + - knowledge-base + - productivity + auth_mode: API_KEY + proxy: + base_url: https://coda.io/apis/v1 + headers: + authorization: Bearer ${apiKey} + docs: https://docs.nango.dev/integrations/all/coda + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Coda account + +codeclimate: + display_name: Code Climate + categories: + - dev-tools + - productivity + auth_mode: API_KEY + proxy: + base_url: https://${connectionConfig.domain} + headers: + accept: application/vnd.api+json + authorization: Token token=${apiKey} + verification: + method: GET + endpoint: /v1/user + docs: https://docs.nango.dev/integrations/all/codeclimate + connection_config: + domain: + type: string + title: Domain + description: The domain of your Code Climate account + format: hostname + prefix: https:// + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Code Climate account + +copper: + display_name: Copper + categories: + - crm + auth_mode: OAUTH2 + proxy: + base_url: https://api.copper.com/developer_api + default_scopes: + - developer/v1/all + authorization_url: https://app.copper.com/oauth/authorize + token_url: https://app.copper.com/oauth/token + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + docs: https://docs.nango.dev/integrations/all/copper + +copper-api-key: + display_name: Copper (api key) + categories: + - crm + auth_mode: API_KEY + proxy: + base_url: https://api.copper.com/developer_api + headers: + x-pw-accesstoken: ${apiKey} + x-pw-application: developer_api + x-pw-useremail: ${connectionConfig.userEmail} + content-type: application/json + verification: + method: GET + endpoint: /v1/account + docs_connect: https://docs.nango.dev/integrations/all/copper/connect + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Copper account + pattern: '^[a-f0-9]{32}$' + example: '4f3c12efb9659a0b5c123b568745dbf9' + doc_section: '#step-1-finding-copper-api-key' + connection_config: + userEmail: + type: string + title: User Email + description: Email address of the user who generated the token + docs: https://docs.nango.dev/integrations/all/copper + +connectwise-psa: + display_name: ConnectWise PSA + categories: + - support + - ticketing + auth_mode: BASIC + proxy: + base_url: https://${connectionConfig.subdomain}.myconnectwise.net/v4_6_release/apis/3.0 + headers: + accept: application/vnd.connectwise.com+json; version=${connectionConfig.apiVersion} + clientid: ${connectionConfig.clientId} + docs: https://docs.nango.dev/integrations/all/connectwise-psa + connection_config: + subdomain: + type: string + title: ConnectWise PSA subdomain + description: The subdomain to connect to ConnectWise PSA + pattern: '^api-(au|eu|na)$' + example: api-au + suffix: .myconnectwise.net + prefix: https:// + apiVersion: + type: string + title: Api version + description: The API version to connect to ConnectWise PSA + clientId: + type: string + title: Client ID + description: The Client ID assigned to your integration + +connectwise-psa-staging: + display_name: ConnectWise PSA (staging) + categories: + - support + - ticketing + auth_mode: BASIC + proxy: + base_url: https://api-staging.connectwisedev.com/v4_6_release/apis/3.0 + headers: + accept: application/vnd.connectwise.com+json; version=${connectionConfig.apiVersion} + clientid: ${connectionConfig.clientId} + docs: https://docs.nango.dev/integrations/all/connectwise-psa + connection_config: + apiVersion: + type: string + title: Api version + description: The API version to connect to ConnectWise PSA + clientId: + type: string + title: Client ID + description: The Client ID assigned to your integration + +confluence: + display_name: Confluence + categories: + - knowledge-base + alias: jira + docs: https://docs.nango.dev/integrations/all/confluence + +contentful: + display_name: Contentful + categories: + - dev-tools + - design + - cms + auth_mode: OAUTH2 + authorization_url: https://be.contentful.com/oauth/authorize + token_url: https://be.contentful.com/oauth/token + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://${connectionConfig.subdomain}.contentful.com + retry: + after: x-contentful-ratelimit-reset + docs: https://docs.nango.dev/integrations/all/contentful + connection_config: + subdomain: + type: string + title: Contentful Domain + description: The subdomain of your Contentful account + pattern: '^[a-z0-9_-]+$' + example: domain + suffix: .contentful.com + prefix: https:// + +contentstack: + display_name: Contentstack + categories: + - cms + auth_mode: OAUTH2 + authorization_url: https://${connectionConfig.subdomain}.contentstack.com/apps/${connectionConfig.appId}/authorize + token_url: https://${connectionConfig.subdomain}.contentstack.com/apps-api/apps/token + docs: https://docs.nango.dev/integrations/all/contentstack + proxy: + base_url: https://${connectionConfig.apiDomain} + connection_config: + subdomain: + type: string + title: Contentstack Domain + description: The subdomain of your Contentstack account + pattern: '^[a-z0-9_-]+$' + example: domain + suffix: .contentstack.com + prefix: https:// + order: 2 + appId: + type: string + title: App ID + description: The app ID of your Contentstack account + order: 1 + apiDomain: + type: string + title: API Domain + description: The domain to where you will access your API + pattern: '^[a-z0-9_-]+$' + example: eu-api.contentstack.com + prefix: https:// + order: 3 + +coros: + display_name: Coros + categories: + - sports + auth_mode: OAUTH2 + authorization_url: https://open.coros.com/oauth2/authorize + token_url: https://open.coros.com/oauth2/accesstoken + refresh_url: https://open.coros.com/oauth2/refresh-token + authorization_params: + response_type: code + token_response_metadata: + - openId + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://open.coros.com + docs: https://docs.nango.dev/integrations/all/coros + +coros-sandbox: + display_name: Coros (sandbox) + auth_mode: OAUTH2 + authorization_url: https://opentest.coros.com/oauth2/authorize + token_url: https://opentest.coros.com/oauth2/accesstoken + refresh_url: https://opentest.coros.com/oauth2/refresh-token + authorization_params: + response_type: code + token_response_metadata: + - openId + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://opentest.coros.com + docs: https://docs.nango.dev/integrations/all/coros + +coupa-compass: + display_name: Coupa Compass + categories: + - payment + - invoicing + auth_mode: OAUTH2_CC + scope_separator: ' ' + token_url: https://${connectionConfig.instanceDomain}/oauth2/token + token_params: + grant_type: client_credentials + proxy: + base_url: https://${connectionConfig.instanceDomain} + docs: https://docs.nango.dev/integrations/all/coupa-compass + connection_config: + instanceDomain: + type: string + title: Instance Domain + description: The domain of your Coupa Compass account + format: hostname + prefix: https:// + +databricks-account: + display_name: Databricks (Account Level) + categories: + - analytics + auth_mode: OAUTH2_CC + token_url: https://accounts.cloud.databricks.com/oidc/accounts/${connectionConfig.accountId}/v1/token + token_params: + grant_type: client_credentials + proxy: + base_url: https://accounts.cloud.databricks.com/api/2.0/accounts/${connectionConfig.accountId} + docs: https://docs.nango.dev/integrations/all/databricks + connection_config: + accountId: + type: string + title: Account ID + description: The ID to your account + format: uuid + example: 123e4567-e89b-12d3-a456-426614174000 + +databricks-workspace: + display_name: Databricks (Workspace Level) + categories: + - analytics + auth_mode: OAUTH2_CC + token_url: https://${connectionConfig.databricksInstance}/oidc/v1/token + token_params: + grant_type: client_credentials + proxy: + base_url: https://${connectionConfig.databricksInstance}/api/2.0/ + docs: https://docs.nango.dev/integrations/all/databricks + connection_config: + databricksInstance: + type: string + title: Databricks Instance + description: The instance to your databricks deployment + pattern: '^[a-z0-9_-]+(\.[a-z0-9_-]+)*$' + example: dbc-a1b2345c-d6e7.cloud.databricks.com + +# Untested configuration. Please reach out if you have a test account that we can use to test it. +datev: + display_name: Datev + categories: + - legal + - hr + auth_mode: OAUTH2 + authorization_url: https://login.datev.de/openid/authorize + token_url: https://api.datev.de/token + token_request_auth_method: basic + scope_separator: ' ' + default_scopes: + - openid + authorization_params: + response_type: code id_token + response_mode: query + nonce: AnotherRandomStringDatev + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://api.datev.de + docs: https://docs.nango.dev/integrations/all/datev + +datadog: + display_name: Datadog + categories: + - analytics + - dev-tools + auth_mode: API_KEY + proxy: + base_url: https://api.${connectionConfig.siteParameter}/api + headers: + dd-api-key: ${apiKey} + dd-application-key: ${connectionConfig.applicationKey} + verification: + method: GET + endpoint: /v1/validate + retry: + after: 'x-ratelimit-reset' + docs: https://docs.nango.dev/integrations/all/datadog + docs_connect: https://docs.nango.dev/integrations/all/datadog/connect + connection_config: + siteParameter: + type: string + title: Site Parameter + description: The site parameter to datadog + pattern: '^(us[35]\.)?(ap1\.)?(datadoghq\.(com|eu)|ddog-gov\.com)$' + example: 'us5.datadoghq.com' + doc_section: '#step-1-finding-your-datadog-domain' + applicationKey: + type: string + title: Application Key + description: The application key required for read data access + pattern: '^[a-f0-9]{40}$' + example: '5d8a7b3f2dc8bce1b234e7f1a1ac54728dbf9e4a7' + doc_section: '#step-3-datadog-application-key' + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Datadog account + pattern: '^[a-f0-9]{32}$' + example: '4f3c12efb9659a0b5c123b568745dbf9' + doc_section: '#step-2-datadog-api-key' + +deel: + display_name: Deel + categories: + - hr + auth_mode: OAUTH2 + authorization_url: https://auth.letsdeel.com/oauth2/authorize + token_url: https://auth.letsdeel.com/oauth2/tokens + token_request_auth_method: basic + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://api.letsdeel.com + docs: https://docs.nango.dev/integrations/all/deel + +deel-sandbox: + display_name: Deel (sandbox) + auth_mode: OAUTH2 + authorization_url: https://auth-demo.letsdeel.com/oauth2/authorize + token_url: https://auth-demo.letsdeel.com/oauth2/tokens + token_request_auth_method: basic + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://api-staging.letsdeel.com + docs: https://docs.nango.dev/integrations/all/deel + +dialpad: + display_name: Dialpad + categories: + - communication + auth_mode: OAUTH2 + authorization_url: https://dialpad.com/oauth2/authorize + token_url: https://dialpad.com/oauth2/token + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://dialpad.com + docs: https://docs.nango.dev/integrations/all/dialpad + +dialpad-sandbox: + display_name: Dialpad (sandbox) + categories: + - communication + auth_mode: OAUTH2 + authorization_url: https://sandbox.dialpad.com/oauth2/authorize + token_url: https://sandbox.dialpad.com/oauth2/token + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://sandbox.dialpad.com + docs: https://docs.nango.dev/integrations/all/dialpad + +digitalocean: + display_name: DigitalOcean + categories: + - dev-tools + auth_mode: OAUTH2 + authorization_url: https://cloud.digitalocean.com/v1/oauth/authorize + token_url: https://cloud.digitalocean.com/v1/oauth/token + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://api.digitalocean.com + docs: https://docs.nango.dev/integrations/all/digitalocean + +discord: + display_name: Discord + categories: + - gaming + - social + auth_mode: OAUTH2 + authorization_url: https://discord.com/api/oauth2/authorize + token_url: https://discord.com/api/oauth2/token + authorization_params: + response_type: code + proxy: + base_url: https://discord.com + retry: + after: 'retry-after' + docs: https://docs.nango.dev/integrations/all/discord + +discourse: + display_name: Discourse + categories: + - communication + auth_mode: API_KEY + proxy: + base_url: https://${connectionConfig.defaultHost} + retry: + after: 'retry-after' + headers: + api-username: ${connectionConfig.apiUsername} + api-key: ${apiKey} + accept: application/json + docs: https://docs.nango.dev/integrations/all/discourse + connection_config: + defaultHost: + type: string + title: Domain + description: The domain of your Discourse account + format: hostname + prefix: https:// + apiUsername: + type: string + title: API Username + description: The API username of your Discourse account + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Discourse account + +dixa: + display_name: Dixa + categories: + - support + auth_mode: API_KEY + proxy: + base_url: https://${connectionConfig.apiType}.dixa.io + headers: + authorization: ${apiKey} + docs: https://docs.nango.dev/integrations/all/dixa + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Dixa account + connection_config: + apiType: + type: string + title: Api Type + description: The Api type for your requests + pattern: '^dev\|exports$' + example: 'dev|exports' + +docusign: + display_name: DocuSign + categories: + - legal + auth_mode: OAUTH2 + authorization_url: https://account.docusign.com/oauth/auth + token_url: https://account.docusign.com/oauth/token + token_request_auth_method: basic + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://www.docusign.net + post_connection_script: docusignPostConnection + docs: https://docs.nango.dev/integrations/all/docusign + +docusign-sandbox: + display_name: DocuSign (sandbox) + auth_mode: OAUTH2 + authorization_url: https://account-d.docusign.com/oauth/auth + token_url: https://account-d.docusign.com/oauth/token + token_request_auth_method: basic + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://demo.docusign.net + post_connection_script: docusignPostConnection + docs: https://docs.nango.dev/integrations/all/docusign + +dropbox: + display_name: Dropbox + categories: + - knowledge-base + - storage + auth_mode: OAUTH2 + authorization_url: https://www.dropbox.com/oauth2/authorize + token_url: https://api.dropboxapi.com/oauth2/token + authorization_params: + token_access_type: offline + proxy: + base_url: https://api.dropboxapi.com + docs: https://docs.nango.dev/integrations/all/dropbox + +emarsys: + display_name: Emarsys Core API (WSSE) + categories: + - marketing + auth_mode: SIGNATURE + signature: + protocol: WSSE + proxy: + base_url: https://api.emarsys.net + headers: + content-type: application/json + x-wsse: ${accessToken} + verification: + method: GET + endpoint: /api/v2/settings + retry: + at: 'x-ratelimit-reset' + token: + expires_in_ms: 300000 + docs: https://docs.nango.dev/integrations/all/emarsys + credentials: + username: + type: string + title: ID + description: The ID of your Emarsys WSSE API Credentials + pattern: '^[a-zA-Z0-9_-]+$' + password: + type: string + title: Client Secret + description: The Client Secret of your Emarsys WSSE API Credentials + pattern: '^[a-zA-Z0-9-]+$' + +emarsys-oauth: + display_name: Emarsys (Ouath) + categories: + - marketing + auth_mode: OAUTH2_CC + token_url: https://auth.emarsys.net/oauth2/token + token_request_auth_method: basic + token_params: + grant_type: client_credentials + proxy: + base_url: https://api.emarsys.net + retry: + at: 'x-ratelimit-reset' + docs: https://docs.nango.dev/integrations/all/emarsys + +ebay: + display_name: eBay + categories: + - e-commerce + auth_mode: OAUTH2 + authorization_url: https://auth.ebay.com/oauth2/authorize + token_url: https://api.ebay.com/identity/v1/oauth2/token + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + token_request_auth_method: basic + proxy: + base_url: https://api.ebay.com/ + docs: https://docs.nango.dev/integrations/all/ebay + +ebay-sandbox: + display_name: eBay (sandbox) + categories: + - e-commerce + auth_mode: OAUTH2 + authorization_url: https://auth.sandbox.ebay.com/oauth2/authorize + token_url: https://api.sandbox.ebay.com/identity/v1/oauth2/token + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + token_request_auth_method: basic + proxy: + base_url: https://api.sandbox.ebay.com/ + docs: https://docs.nango.dev/integrations/all/ebay + +e-conomic: + display_name: e-conomic + categories: + - accounting + auth_mode: BASIC + proxy: + base_url: https://restapi.e-conomic.com + headers: + content-type: application/json + docs: https://docs.nango.dev/integrations/all/e-conomic + +egnyte: + display_name: Egnyte + categories: + - storage + auth_mode: OAUTH2 + authorization_url: https://${connectionConfig.subdomain}.egnyte.com/puboauth/token + token_url: https://${connectionConfig.subdomain}.egnyte.com/puboauth/token + scope_separator: ' ' + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://${connectionConfig.subdomain}.egnyte.com/pubapi + docs: https://docs.nango.dev/integrations/all/egnyte + connection_config: + subdomain: + type: string + title: Egnyte Domain + description: The subdomain of your Egnyte account + pattern: '^[a-z0-9_-]+$' + example: domain + suffix: .egnyte.com + prefix: https:// + +elevenlabs: + display_name: Eleven Labs + categories: + - dev-tools + auth_mode: API_KEY + proxy: + base_url: https://api.elevenlabs.io + headers: + xi-api-key: ${apiKey} + verification: + method: GET + endpoint: /v1/user + docs: https://docs.nango.dev/integrations/all/elevenlabs + credentials: + apiKey: + type: string + title: API Key + description: The API key for your ElevenLabs account + +elevio: + display_name: Elevio + categories: + - knowledge-base + - support + auth_mode: API_KEY + proxy: + base_url: https://api.elev.io + headers: + x-api-key: ${apiKey} + authorization: Bearer ${connectionConfig.jwt} + docs: https://docs.nango.dev/integrations/all/elevio + credentials: + apiKey: + type: string + title: API Key + description: The API key to your Elevio account + pattern: '\b[a-f0-9]{40}\b' + example: 'x12z67890dd34t8gq5j01ycc75912348' + connection_config: + jwt: + type: string + title: JWT + description: The JWT to your Elevio account + pattern: '^[A-Za-z0-9-_]+\.([A-Za-z0-9-_]+\.[A-Za-z0-9-_]+)$' + +entrata: + display_name: Entrata + categories: + - other + auth_mode: BASIC + proxy: + base_url: https://${connectionConfig.subdomain}.entrata.com + docs: https://docs.nango.dev/integrations/all/entrata + connection_config: + subdomain: + type: string + title: Entrata Domain + description: The subdomain of your Entrata account + pattern: '^[a-z0-9_-]+$' + example: domain + suffix: .entrata.com + prefix: https:// + +envoy: + display_name: Envoy + categories: + - productivity + auth_mode: OAUTH2 + authorization_url: https://app.envoy.com/a/auth/v0/authorize + token_url: https://app.envoy.com/a/auth/v0/token + scope_separator: ' ' + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://api.envoy.com + docs: https://docs.nango.dev/integrations/all/envoy + +epic-games: + display_name: Epic Games + categories: + - gaming + auth_mode: OAUTH2 + authorization_url: https://www.epicgames.com/id/authorize + token_url: https://api.epicgames.dev/epic/oauth/v1/token + authorization_method: header + proxy: + base_url: https://api.epicgames.dev + docs: https://docs.nango.dev/integrations/all/epic-games + +evaluagent: + display_name: EvaluAgent + auth_mode: BASIC + proxy: + base_url: https://${connectionConfig.region}.evaluagent.com + verification: + method: GET + endpoint: /v1/ping + docs: https://docs.nango.dev/integrations/all/evaluagent + connection_config: + region: + type: string + title: Region + description: The region of your EvaluAgent account + example: eu + pattern: '^[a-z]+$' + +eventbrite: + display_name: Eventbrite + categories: + - marketing + auth_mode: OAUTH2 + authorization_url: https://www.eventbrite.com/oauth/authorize + token_url: https://www.eventbrite.com/oauth/token + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + proxy: + base_url: https://www.eventbriteapi.com + docs: https://docs.nango.dev/integrations/all/eventbrite + +exa: + display_name: Exa + categories: + - analytics + auth_mode: API_KEY + proxy: + base_url: https://api.exa.ai + headers: + x-api-key: ${apiKey} + docs: https://docs.nango.dev/integrations/all/exa + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Exa account + +exact-online: + display_name: Exact Online + categories: + - accounting + - hr + - productivity + auth_mode: OAUTH2 + authorization_url: https://start.exactonline.${connectionConfig.extension}/api/oauth2/auth + token_url: https://start.exactonline.${connectionConfig.extension}/api/oauth2/token + authorization_method: header + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + token_expiration_buffer: 30 + proxy: + base_url: https://start.exactonline.${connectionConfig.extension}/ + headers: + accept: application/json + retry: + at: 'x-ratelimit-reset' + paginate: + type: link + link_path_in_response_body: d.__next + docs: https://docs.nango.dev/integrations/all/exact-online + connection_config: + extension: + type: string + title: Domain Extension + description: The domain extension of your Exact Online account + example: nl + pattern: '^[a-z.]+$' + +exist: + display_name: Exist + categories: + - other + auth_mode: OAUTH2 + authorization_url: https://exist.io/oauth2/authorize + token_url: https://exist.io/oauth2/access_token + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://exist.io/ + paginate: + type: link + link_path_in_response_body: next + docs: https://docs.nango.dev/integrations/all/exist + +expensify: + display_name: Expensify + categories: + - productivity + auth_mode: BASIC + proxy: + base_url: https://integrations.expensify.com/Integration-Server/ + headers: + content-type: application/x-www-form-urlencoded + credentials: + username: + type: string + title: Partner User ID + description: Your unique account identifier of Expensify + doc_section: '#step-1-finding-your-partneruserid-and-partnerusersecret' + password: + type: string + title: Partner User Secret + description: Unique secret for your account + doc_section: '#step-1-finding-your-partneruserid-and-partnerusersecret' + docs: https://docs.nango.dev/integrations/all/expensify + docs_connect: https://docs.nango.dev/integrations/all/expensify/connect + +factorial: + display_name: Factorial + categories: + - hr + auth_mode: OAUTH2 + authorization_url: https://api.factorialhr.com/oauth/authorize + token_url: https://api.factorialhr.com/oauth/token + disable_pkce: true + proxy: + base_url: https://api.factorialhr.com/api + docs: https://docs.nango.dev/integrations/all/factorial + +facebook: + display_name: Facebook + categories: + - marketing + - social + auth_mode: OAUTH2 + authorization_url: https://www.facebook.com/v15.0/dialog/oauth + token_url: https://graph.facebook.com/v15.0/oauth/access_token + proxy: + base_url: https://graph.facebook.com + docs: https://docs.nango.dev/integrations/all/facebook + +figjam: + display_name: FigJam + categories: + - design + - productivity + alias: figma + docs: https://docs.nango.dev/integrations/all/figjam + +figma: + display_name: Figma + categories: + - design + - productivity + auth_mode: OAUTH2 + authorization_url: https://www.figma.com/oauth + token_url: https://www.figma.com/api/oauth/token + refresh_url: https://www.figma.com/api/oauth/refresh + disable_pkce: true + proxy: + base_url: https://api.figma.com + docs: https://docs.nango.dev/integrations/all/figma + +falai: + display_name: fal.ai + categories: + - productivity + - dev-tools + auth_mode: API_KEY + proxy: + headers: + authorization: Key ${apiKey} + base_url: https://queue.fal.run + docs: https://docs.nango.dev/integrations/all/falai + credentials: + apiKey: + type: string + title: API Key + description: The API key for your fal.ai account + +findymail: + display_name: FindyMail + categories: + - marketing + - crm + auth_mode: API_KEY + proxy: + base_url: https://app.findymail.com + headers: + authorization: Bearer ${apiKey} + docs: https://docs.nango.dev/integrations/all/findymail + docs_connect: https://docs.nango.dev/integrations/all/findymail/connect + credentials: + apiKey: + type: string + title: API Key + description: The API key for your FindyMail account + +firefish: + display_name: Firefish + scope_separator: ' ' + categories: + - crm + auth_mode: OAUTH2_CC + token_url: https://api.firefishsoftware.com/authorization/token + token_params: + grant_type: client_credentials + proxy: + base_url: https://api.firefishsoftware.com + docs: https://docs.nango.dev/integrations/all/firefish + +fireflies: + display_name: Fireflies + categories: + - analytics + - communication + - productivity + auth_mode: API_KEY + proxy: + base_url: https://api.fireflies.ai + headers: + authorization: Bearer ${apiKey} + docs: https://docs.nango.dev/integrations/all/fireflies + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Fireflies account + +fiserv: + display_name: Fiserv + categories: + - banking + - payment + auth_mode: OAUTH2_CC + token_url: https://cert.api.fiservapps.com/fts-apim/oauth2/v2 + token_request_auth_method: basic + expires_in_unit: milliseconds + token_params: + grant_type: client_credentials + proxy: + base_url: https://${connectionConfig.hostUrl} + docs: https://docs.nango.dev/integrations/all/fiserv + connection_config: + hostUrl: + type: string + title: Domain + description: The domain of your Fiserv account + format: hostname + prefix: https:// + +fiserv-api-key: + display_name: Fiserv (api key) + categories: + - banking + - payment + auth_mode: API_KEY + proxy: + base_url: https://prod.emea.api.fiservapps.com + headers: + api-key: ${apiKey} + verification: + method: GET + endpoint: /sandbox/exp/v1/authorisations + docs: https://docs.nango.dev/integrations/all/fiserv + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Fiserv account + +fitbit: + display_name: Fitbit + categories: + - sports + auth_mode: OAUTH2 + authorization_url: https://www.fitbit.com/oauth2/authorize + token_url: https://api.fitbit.com/oauth2/token + authorization_method: header + proxy: + base_url: https://api.fitbit.com + docs: https://docs.nango.dev/integrations/all/fitbit + +fortnox: + display_name: Fortnox + categories: + - accounting + - invoicing + auth_mode: OAUTH2 + authorization_url: https://apps.fortnox.se/oauth-v1/auth + token_url: https://apps.fortnox.se/oauth-v1/token + token_request_auth_method: basic + scope_separator: ' ' + authorization_params: + response_type: code + access_type: offline + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://api.fortnox.se/3 + docs: https://docs.nango.dev/integrations/all/fortnox + +freshbooks: + display_name: FreshBooks + categories: + - accounting + auth_mode: OAUTH2 + authorization_url: https://auth.freshbooks.com/oauth/authorize + token_url: https://api.freshbooks.com/auth/oauth/token + authorization_params: + response_type: code + proxy: + base_url: https://api.freshbooks.com + docs: https://docs.nango.dev/integrations/all/freshbooks + +freshdesk: + display_name: FreshDesk + categories: + - support + auth_mode: BASIC + proxy: + base_url: https://${connectionConfig.subdomain}.freshdesk.com + verification: + endpoint: /api/v2/settings/helpdesk + docs: https://docs.nango.dev/integrations/all/freshdesk + docs_connect: https://docs.nango.dev/integrations/all/freshdesk/connect + credentials: + username: + type: string + title: FreshDesk API Key + description: The API Key of your FreshDesk account + doc_section: '#step-1-finding-your-freshdesk-api-key' + secret: true + password: + type: string + title: '' + description: '' + default_value: X + hidden: true + connection_config: + subdomain: + type: string + title: FreshDesk Domain + description: The subdomain of your FreshDesk account + pattern: '^[a-z0-9_-]+$' + example: domain + suffix: .freshdesk.com + prefix: https:// + doc_section: '#step-2-finding-your-freshdesk-domain' + +freshsales: + display_name: Freshsales + categories: + - crm + auth_mode: API_KEY + proxy: + base_url: https://${connectionConfig.subdomain}.freshsales.io + verification: + method: GET + endpoint: /api/settings/leads/fields + headers: + authorization: Token token=${apiKey} + retry: + after: 'retry-after' + docs: https://docs.nango.dev/integrations/all/freshsales + docs_connect: https://docs.nango.dev/integrations/all/freshsales/connect + connection_config: + subdomain: + type: string + title: Freshsales subdomain + description: The subdomain of your Freshsales account + pattern: '^[a-z0-9_-]+$' + example: subdomain + suffix: .freshsales.io + prefix: https:// + doc_section: '#step-2-finding-your-freshsales-subdomain' + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Freshsales account + example: 4oBqA_AzM_G3xbW3TJGvrA + pattern: '[A-Za-z0-9_]{22}' + doc_section: '#step-1-finding-your-freshsales-api-key' + +freshservice: + display_name: Freshservice + categories: + - support + auth_mode: BASIC + proxy: + base_url: https://${connectionConfig.subdomain}.freshservice.com + verification: + method: GET + endpoint: /api/v2/tickets + retry: + after: 'retry-after' + docs: https://docs.nango.dev/integrations/all/freshservice + docs_connect: https://docs.nango.dev/integrations/all/freshservice/connect + connection_config: + subdomain: + type: string + title: Freshservice subdomain + description: The subdomain of your Freshservice account + pattern: '^[a-z0-9_-]+$' + example: subdomain + suffix: .freshservice.com + prefix: https:// + doc_section: '#step-2-finding-your-freshservice-subdomain' + credentials: + username: + type: string + title: API key + description: The API Key of your Freshservice account + secret: true + doc_section: '#step-1-finding-your-freshservice-api-key' + password: + type: string + title: '' + description: '' + # https://api.freshservice.com/#authentication + # FreshService is using basic auth with an api key, the basic username/password was deprecated + default_value: 'X' + hidden: true + +freshteam: + display_name: Freshteam + categories: + - hr + auth_mode: API_KEY + proxy: + base_url: https://${connectionConfig.accountName}.freshteam.com + headers: + authorization: Bearer ${apiKey} + accept: application/json + docs: https://docs.nango.dev/integrations/all/freshteam + docs_connect: https://docs.nango.dev/integrations/all/freshteam/connect + connection_config: + accountName: + type: string + title: Account Name + description: The account name of your Freshteam account + example: nango + format: hostname + suffix: .freshteam.com + prefix: https:// + order: 1 + doc_section: '#step-1-finding-your-account-name' + credentials: + apiKey: + type: string + title: API Key + description: The API key to your Freshteam account + doc_section: '#step-2-finding-your-api-key' + example: 'XtoF94LMNyKPbd5AvR1QJh' + pattern: '^[a-zA-Z0-9_!@#$%^&*()\\-+=]+$' + +front: + display_name: Front + categories: + - support + - ticketing + auth_mode: OAUTH2 + authorization_url: https://app.frontapp.com/oauth/authorize + token_url: https://app.frontapp.com/oauth/token + proxy: + base_url: https://api2.frontapp.com + retry: + after: 'retry-after' + paginate: + type: link + response_path: _results + link_path_in_response_body: _pagination.next + docs: https://docs.nango.dev/integrations/all/front + +gainsight-cc: + display_name: Gainsight CC + categories: + - support + - crm + auth_mode: OAUTH2_CC + token_url: https://api2-${connectionConfig.region}.insided.com/oauth2/token + scope_separator: ' ' + token_params: + grant_type: client_credentials + proxy: + base_url: https://api2-${connectionConfig.region}.insided.com + docs: https://docs.nango.dev/integrations/all/gainsight-cc + docs_connect: https://docs.nango.dev/integrations/all/gainsight-cc/connect + connection_config: + region: + type: string + title: Region + description: The region of your Gainsight account + example: eu-west-1 + pattern: '^[a-z]{2}-[a-z]+-[1-9]$' + doc_section: '#step-2-finding-your-region' + +garmin: + display_name: Garmin + categories: + - sports + auth_mode: OAUTH1 + request_url: https://connectapi.garmin.com/oauth-service/oauth/request_token + authorization_url: https://connect.garmin.com/oauthConfirm + token_url: https://connectapi.garmin.com/oauth-service/oauth/access_token + signature_method: 'HMAC-SHA1' + proxy: + base_url: https://apis.garmin.com + docs: https://docs.nango.dev/integrations/all/garmin + +gerrit: + display_name: Gerrit + categories: + - dev-tools + auth_mode: BASIC + proxy: + base_url: https://${connectionConfig.host} + verification: + method: GET + endpoint: /config/server/version + docs: https://docs.nango.dev/integrations/all/gerrit + docs_connect: https://docs.nango.dev/integrations/all/gerrit/connect + connection_config: + host: + type: string + title: Gerrit Host + description: The host to where you Gerrit instance is hosted + pattern: '^https?:\/\/[a-z0-9.-]+(:\d+)?(\/.*)?$' + example: http://localhost:8080 + doc_section: '#step-1-finding-your-host' + order: 1 + +guru: + display_name: Guru + categories: + - knowledge-base + auth_mode: BASIC + proxy: + base_url: https://api.getguru.com/api/v1 + verification: + method: GET + endpoint: /whoami + docs: https://docs.nango.dev/integrations/all/guru + docs_connect: https://docs.nango.dev/integrations/all/guru/connect + credentials: + username: + type: string + title: User/Collection ID + description: The user or collection ID of your Guru account + doc_section: '#step-1-finding-your-user-collection-id' + password: + type: string + title: User/Collection Token + description: The user or collection token of your Guru account + secret: true + format: uuid + example: 123e4567-e89b-12d3-a456-426614174000 + doc_section: '#step-2-generating-your-user-collection-token' + +github: + display_name: GitHub + categories: + - dev-tools + - support + - ticketing + auth_mode: OAUTH2 + authorization_url: https://github.com/login/oauth/authorize + token_url: https://github.com/login/oauth/access_token + proxy: + base_url: https://api.github.com + retry: + at: 'x-ratelimit-reset' + remaining: 'x-ratelimit-remaining' + error_code: 403 + paginate: + type: link + limit_name_in_request: per_page + link_rel_in_response_header: next + docs: https://docs.nango.dev/integrations/all/github + +github-app: + display_name: GitHub App + categories: + - dev-tools + - ticketing + alias: github + auth_mode: APP + authorization_url: ${connectionConfig.appPublicLink}/installations/new + token_url: https://api.github.com/app/installations/${connectionConfig.installation_id}/access_tokens + webhook_routing_script: githubAppWebhookRouting + docs: https://docs.nango.dev/integrations/all/github + connection_config: + appPublicLink: + type: string + title: App Public Link + description: The public link of your GitHub App + format: uri + pattern: '^https?://.*$' + installation_id: + type: string + title: Installation ID + description: The installation ID of your GitHub App + example: '38631545' + automated: true + +github-app-oauth: + display_name: GitHub App (oauth) + categories: + - dev-tools + - ticketing + alias: github + auth_mode: CUSTOM + authorization_url: ${connectionConfig.appPublicLink}/installations/new + authorization_url_skip_encode: + - base_url + token_url: + OAUTH2: https://github.com/login/oauth/access_token + APP: https://api.github.com/app/installations/${connectionConfig.installation_id}/access_tokens + webhook_routing_script: githubAppOauthWebhookRouting + post_connection_script: githubAppOauthPostConnection + docs: https://docs.nango.dev/integrations/all/github + connection_config: + appPublicLink: + type: string + title: App Public Link + description: The public link of your GitHub App + format: uri + pattern: '^https?://.*$' + installation_id: + type: string + title: Installation ID + description: The installation ID of your GitHub App + example: '38631545' + automated: true + +gitlab: + display_name: GitLab + categories: + - dev-tools + - ticketing + auth_mode: OAUTH2 + authorization_url: https://gitlab.com/oauth/authorize + token_url: https://gitlab.com/oauth/token + authorization_params: + response_type: code + proxy: + base_url: https://gitlab.com + docs: https://docs.nango.dev/integrations/all/gitlab + +ghost-admin: + display_name: Ghost (Admin API) + categories: + - dev-tools + - design + - cms + auth_mode: JWT + token: + expires_in_ms: 300000 + headers: + alg: HS256 + payload: + aud: /admin/ + proxy: + headers: + accept: application/json + accept-version: ${connectionConfig.version} + base_url: https://${connectionConfig.adminDomain}/ghost/api/admin/ + docs: https://docs.nango.dev/integrations/all/ghost + connection_config: + adminDomain: + type: string + title: Ghost Admin Domain + description: The domain of your Ghost Admin which can be different from your main domain + example: 'mock.ghost.io' + pattern: '^([a-z0-9_-]+\.|)(ghost\.io|[a-z0-9_-]+\.[a-z]{2,})$' + version: + type: string + title: API Version + description: The version of the Ghost Admin API to use + example: 'v3.0' + pattern: '^v\d+\.\d+$' + +ghost-content: + display_name: Ghost (Content API) + categories: + - dev-tools + - design + - cms + auth_mode: API_KEY + proxy: + headers: + accept-version: ${connectionConfig.version} + base_url: https://${connectionConfig.adminDomain}/ghost/api/content/ + query: + key: ${apiKey} + verification: + method: GET + endpoint: /tags + docs: https://docs.nango.dev/integrations/all/ghost + connection_config: + version: + type: string + title: API Version + description: The version of the Ghost Admin API to use + example: 'v3.0' + pattern: '^v\d+\.\d+$' + adminDomain: + type: string + title: Ghost Admin Domain + description: The domain of your Ghost Admin which can be different from your main domain + example: 'mock.ghost.io' + pattern: '^([a-z0-9_-]+\.|)(ghost\.io|[a-z0-9_-]+\.[a-z]{2,})$' + credentials: + apiKey: + type: string + title: API Key + description: The content API key for your Ghost account + pattern: '^[a-zA-Z0-9]{26}$' + example: a1b2c3d4e5f6g7h8i9j0k1l2m3 + +gong: + display_name: Gong + categories: + - productivity + auth_mode: BASIC + proxy: + base_url: https://api.gong.io + retry: + after: 'retry-after' + docs: https://docs.nango.dev/integrations/all/gong + docs_connect: https://docs.nango.dev/integrations/all/gong/connect + credentials: + username: + type: string + title: Access Key + description: Your Gong Access Key + pattern: '^[a-zA-Z0-9-]+$' + doc_section: '#step-1-finding-gong-api-key-and-api-key-secret' + password: + type: string + title: Access Key Secret + description: Your Gong Access Key Secret + default_value: '' + doc_section: '#step-1-finding-gong-api-key-and-api-key-secret' + +gong-oauth: + display_name: Gong (oauth) + auth_mode: OAUTH2 + categories: + - productivity + authorization_url: https://app.gong.io/oauth2/authorize + token_url: https://app.gong.io/oauth2/generate-customer-token + token_response_metadata: + - api_base_url_for_customer + authorization_params: + response_type: code + access_type: offline + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + disable_pkce: true + token_request_auth_method: basic + proxy: + base_url: ${connectionConfig.api_base_url_for_customer} || https://api.gong.io + retry: + after: 'retry-after' + docs: https://docs.nango.dev/integrations/all/gong + connection_config: + api_base_url_for_customer: + type: string + title: API Base URL + description: The base URL of your Gong account + format: uri + pattern: '^https?://.*$' + +google: + display_name: Google + auth_mode: OAUTH2 + authorization_url: https://accounts.google.com/o/oauth2/v2/auth + token_url: https://oauth2.googleapis.com/token + authorization_params: + response_type: code + access_type: offline + prompt: consent + proxy: + base_url: https://www.googleapis.com + paginate: + type: cursor + cursor_path_in_response: nextPageToken + limit_name_in_request: maxSize + cursor_name_in_request: pageToken + response_path: items + docs: https://docs.nango.dev/integrations/all/google + +google-analytics: + display_name: Google Analytics + alias: google + categories: + - analytics + docs: https://docs.nango.dev/integrations/all/google-analytics + +google-calendar: + display_name: Google Calendar + categories: + - productivity + alias: google + proxy: + base_url: https://www.googleapis.com + paginate: + type: cursor + cursor_path_in_response: nextPageToken + limit_name_in_request: maxSize + cursor_name_in_request: pageToken + response_path: items + docs: https://docs.nango.dev/integrations/all/google-calendar + +google-docs: + display_name: Google Docs + categories: + - productivity + alias: google + proxy: + base_url: https://docs.googleapis.com + docs: https://docs.nango.dev/integrations/all/google-docs + +google-mail: + display_name: Google Mail + categories: + - productivity + alias: google + proxy: + base_url: https://gmail.googleapis.com + docs: https://docs.nango.dev/integrations/all/google-mail + +google-sheet: + display_name: Google Sheet + categories: + - productivity + alias: google + proxy: + base_url: https://sheets.googleapis.com + docs: https://docs.nango.dev/integrations/all/google-sheet + +google-drive: + display_name: Google Drive + categories: + - knowledge-base + - storage + alias: google + docs: https://docs.nango.dev/integrations/all/google-drive + +google-ads: + display_name: Google Ads + categories: + - marketing + alias: google + token_url: https://www.googleapis.com/oauth2/v3/token + proxy: + base_url: https://googleads.googleapis.com + paginate: + type: cursor + cursor_path_in_response: nextPageToken + limit_name_in_request: pageSize + cursor_name_in_request: pageToken + response_path: results + docs: https://docs.nango.dev/integrations/all/google-ads + +google-play: + display_name: Google Play + categories: + - dev-tools + auth_mode: OAUTH2 + authorization_url: https://accounts.google.com/o/oauth2/auth + token_url: https://accounts.google.com/o/oauth2/token + authorization_params: + response_type: code + access_type: offline + prompt: consent + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://play.googleapis.com + docs: https://docs.nango.dev/integrations/all/google-play + +gorgias: + display_name: Gorgias + categories: + - e-commerce + auth_mode: OAUTH2 + authorization_url: https://${connectionConfig.subdomain}.gorgias.com/oauth/authorize + token_url: https://${connectionConfig.subdomain}.gorgias.com/oauth/token + token_request_auth_method: basic + default_scopes: + - offline + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://${connectionConfig.subdomain}.gorgias.com + retry: + after: 'retry-after' + docs: https://docs.nango.dev/integrations/all/gorgias + connection_config: + subdomain: + type: string + title: Gorgias Domain + description: The subdomain of your Gorgias account + pattern: '^[a-z0-9_-]+$' + example: domain + suffix: .gorgias.com + prefix: https:// + +grain: + display_name: Grain + categories: + - video + - communication + - productivity + auth_mode: OAUTH2 + authorization_url: https://grain.com/_/public-api/oauth2/authorize + token_url: https://api.grain.com/_/public-api/oauth2/token + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + proxy: + base_url: https://api.grain.com + docs: https://docs.nango.dev/integrations/all/grain + +grain-api-key: + display_name: Grain (api key) + categories: + - video + - communication + - productivity + auth_mode: API_KEY + proxy: + base_url: https://api.grain.com + verification: + method: GET + endpoint: /_/public-api/me + headers: + authorization: Bearer ${apiKey} + docs: https://docs.nango.dev/integrations/all/grain + credentials: + apiKey: + type: string + title: API Key + description: The personal access token to your Grain account + +greenhouse: + display_name: Greenhouse + categories: + - ats + auth_mode: OAUTH2 + authorization_url: https://api.greenhouse.io/oauth/authorize + token_url: https://api.greenhouse.io/oauth/token + proxy: + base_url: https://${connectionConfig.resource}.greenhouse.io + retry: + after: 'retry-after' + paginate: + type: link + limit_name_in_request: per_page + link_rel_in_response_header: next + docs: https://docs.nango.dev/integrations/all/greenhouse + connection_config: + resource: + type: string + title: Greenhouse API Domain + description: The Greenhouse API Domain you want to connect to + pattern: '^[a-z0-9_-]+$' + example: harvest + suffix: .greenhouse.io + prefix: https:// + +greenhouse-basic: + display_name: Greenhouse (basic auth) + categories: + - ats + auth_mode: BASIC + proxy: + base_url: https://${connectionConfig.resource}.greenhouse.io + retry: + after: 'retry-after' + paginate: + type: link + limit_name_in_request: per_page + link_rel_in_response_header: next + docs: https://docs.nango.dev/integrations/all/greenhouse + docs_connect: https://docs.nango.dev/integrations/all/greenhouse-basic/connect + connection_config: + resource: + type: string + title: Greenhouse API Domain + description: The Greenhouse API Domain you want to connect to + pattern: '^[a-z0-9_-]+$' + example: harvest + suffix: .greenhouse.io + prefix: https:// + order: 1 + credentials: + username: + type: string + title: API key + description: The API Key of your Greenhouse account + pattern: '^[a-zA-Z0-9-]+$' + secret: true + doc_section: '#step-1-finding-greenhouse-api-key' + password: + type: string + title: Password + description: Password + # https://developers.greenhouse.io/harvest.html#authentication + # Greenhouse is using basic auth with an api key + default_value: '' + hidden: true + +gumroad: + display_name: Gumroad + categories: + - design + - e-commerce + - payment + auth_mode: OAUTH2 + authorization_url: https://gumroad.com/oauth/authorize + token_url: https://api.gumroad.com/oauth/token + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://api.gumroad.com + docs: https://docs.nango.dev/integrations/all/gumroad + +gusto: + display_name: Gusto + categories: + - hr + auth_mode: OAUTH2 + authorization_url: https://api.gusto.com/oauth/authorize + token_url: https://api.gusto.com/oauth/token + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://api.gusto.com + post_connection_script: gustoPostConnection + docs: https://docs.nango.dev/integrations/all/gusto + +gusto-demo: + display_name: Gusto (demo) + auth_mode: OAUTH2 + authorization_url: https://api.gusto-demo.com/oauth/authorize + token_url: https://api.gusto-demo.com/oauth/token + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://api.gusto-demo.com + post_connection_script: gustoPostConnection + docs: https://docs.nango.dev/integrations/all/gusto + +hackerrank-work: + display_name: HackerRank Work + auth_mode: BASIC + proxy: + base_url: https://www.hackerrank.com + verification: + method: GET + endpoint: /x/api/v3/users?limit=10&offset=10 + docs: https://docs.nango.dev/integrations/all/hackerrank-work + docs_connect: https://docs.nango.dev/integrations/all/hackerrank-work/connect + credentials: + username: + type: string + title: API Key + description: Your HackerRank Work API Key + doc_section: '#step-1-finding-hackerrank-api-key' + password: + type: string + title: '' + description: '' + default_value: '' + hidden: true + +harvest: + display_name: Harvest + categories: + - productivity + auth_mode: OAUTH2 + authorization_url: https://id.getharvest.com/oauth2/authorize + token_url: https://id.getharvest.com/api/v2/oauth2/token + scope_separator: ' ' + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + headers: + user-agent: ${connectionConfig.appDetails} || App (support@nango.dev) + retry: + after: 'retry-after' + base_url: https://api.harvestapp.com + docs: https://docs.nango.dev/integrations/all/harvest + connection_config: + appDetails: + type: string + title: App Details + description: The details of your app + automated: true + +health-gorilla: + display_name: Health Gorilla + auth_mode: OAUTH2 + authorization_url: https://api.healthgorilla.com/oauth/authorize + token_url: https://api.healthgorilla.com/oauth/token + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://healthgorilla.com + docs: https://docs.nango.dev/integrations/all/healthgorilla + +hibob-service-user: + display_name: Hibob Service User + categories: + - hr + auth_mode: BASIC + proxy: + base_url: https://api.hibob.com + verification: + method: GET + endpoint: /v1/company/named-lists + retry: + at: 'x-ratelimit-reset' + credentials: + username: + type: string + title: User name + description: Your Hibob ID + doc_section: '#step-1-finding-your-hibob-service-user-id' + password: + type: string + title: Password + description: Your Hibob Token + default_value: '' + hidden: true + doc_section: '#step-2-finding-your-hibob-token' + docs: https://docs.nango.dev/integrations/all/hibob + docs_connect: https://docs.nango.dev/integrations/all/hibob-service-user/connect + +highlevel: + display_name: HighLevel + categories: + - marketing + auth_mode: OAUTH2 + authorization_url: https://marketplace.gohighlevel.com/oauth/chooselocation + token_url: https://services.leadconnectorhq.com/oauth/token + scope_separator: ' ' + proxy: + base_url: https://services.leadconnectorhq.com + disable_pkce: true + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + docs: https://docs.nango.dev/integrations/all/highlevel + +highlevel-white-label: + display_name: HighLevel (white label) + categories: + - marketing + auth_mode: OAUTH2 + authorization_url: https://marketplace.leadconnectorhq.com/oauth/chooselocation + token_url: https://services.leadconnectorhq.com/oauth/token + scope_separator: ' ' + proxy: + base_url: https://services.leadconnectorhq.com + disable_pkce: true + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + docs: https://docs.nango.dev/integrations/all/highlevel + +holded: + display_name: Holded + categories: + - accounting + - crm + - invoicing + auth_mode: API_KEY + proxy: + base_url: https://api.holded.com/api + headers: + key: ${apiKey} + verification: + method: GET + endpoint: /invoicing/v1/contacts + docs: https://docs.nango.dev/integrations/all/holded + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Holded account + +hubspot: + display_name: HubSpot + categories: + - marketing + - support + - crm + auth_mode: OAUTH2 + authorization_url: https://app.hubspot.com/oauth/authorize + token_url: https://api.hubapi.com/oauth/v1/token + connection_configuration: + - portalId + post_connection_script: hubspotPostConnection + webhook_routing_script: hubspotWebhookRouting + proxy: + base_url: https://api.hubapi.com + decompress: true + paginate: + type: cursor + cursor_path_in_response: paging.next.after + limit_name_in_request: limit + cursor_name_in_request: after + response_path: results + docs: https://docs.nango.dev/integrations/all/hubspot + +insightly: + display_name: Insightly + categories: + - crm + auth_mode: BASIC + proxy: + base_url: https://api.${connectionConfig.pod}.insightly.com + verification: + method: GET + endpoint: /v3.1/Contacts + docs: https://docs.nango.dev/integrations/all/insightly + connection_config: + pod: + type: string + title: Insightly Domain + description: The subdomain of your Insightly account + pattern: '^[a-z0-9_-]+$' + example: domain + suffix: .insightly.com + prefix: https:// + credentials: + username: + type: string + title: API Key + description: Your Insightly API key + password: + type: string + title: '' + description: '' + hidden: true + default_value: '' + +instantly: + display_name: Instantly + categories: + - marketing + - communication + auth_mode: API_KEY + proxy: + base_url: https://api.instantly.ai/api + docs: https://docs.nango.dev/integrations/all/instantly + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Instantly account + +instagram: + display_name: Instagram + categories: + - marketing + - social + auth_mode: OAUTH2 + authorization_url: https://api.instagram.com/oauth/authorize + token_url: https://api.instagram.com/oauth/access_token + proxy: + base_url: https://graph.instagram.com + docs: https://docs.nango.dev/integrations/all/instagram + +intercom: + display_name: Intercom + categories: + - marketing + - support + - surveys + - ticketing + auth_mode: OAUTH2 + authorization_url: https://app.intercom.io/oauth + token_url: https://api.intercom.io/auth/eagle/token + proxy: + base_url: https://api.intercom.io + retry: + at: 'x-ratelimit-reset' + docs: https://docs.nango.dev/integrations/all/intercom + +intuit: + display_name: Intuit + categories: + - accounting + auth_mode: OAUTH2 + authorization_url: https://appcenter.intuit.com/connect/oauth2 + token_url: https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer + proxy: + base_url: https://quickbooks.api.intuit.com + docs: https://docs.nango.dev/integrations/all/intuit + +jira: + display_name: Jira + categories: + - productivity + - ticketing + auth_mode: OAUTH2 + authorization_url: https://auth.atlassian.com/authorize + token_url: https://auth.atlassian.com/oauth/token + authorization_params: + audience: api.atlassian.com + prompt: consent + connection_configuration: + - cloudId + - accountId + proxy: + base_url: https://api.atlassian.com + paginate: + type: link + link_rel_in_response_header: next + limit_name_in_request: limit + response_path: results + link_path_in_response_body: _links.next + post_connection_script: jiraPostConnection + webhook_routing_script: jiraWebhookRouting + docs: https://docs.nango.dev/integrations/all/jira + +jira-basic: + display_name: Jira (basic auth) + categories: + - productivity + - ticketing + auth_mode: BASIC + proxy: + retry: + after: 'retry-after' + base_url: https://${connectionConfig.subdomain}.atlassian.net + verification: + method: GET + endpoint: /rest/api/3/events + docs: https://docs.nango.dev/integrations/all/jira + connection_config: + subdomain: + type: string + title: Jira Domain + description: The subdomain of your Jira account + pattern: '^[a-z0-9_-]+$' + example: domain + suffix: .atlassian.net + prefix: https:// + order: 1 + doc_section: '#step-2-finding-your-atlassian-domain' + credentials: + username: + type: string + title: Email Address + description: The Email Address of your Jira account + format: email + doc_section: '#step-3-finding-your-user-name' + password: + type: string + title: API Key + description: The API Key of your Jira account + doc_section: '#step-1-finding-atlassian-api-key' + docs_connect: https://docs.nango.dev/integrations/all/jira-basic/connect + +jira-data-center: + display_name: Jira Data Center + categories: + - productivity + - ticketing + auth_mode: OAUTH2 + authorization_url: https://${connectionConfig.endpointURL}/rest/oauth2/latest/authorize + authorization_params: + grant_type: authorization_code + token_url: https://${connectionConfig.endpointURL}/rest/oauth2/latest/token + docs: https://docs.nango.dev/integrations/all/jira-data-center + proxy: + base_url: https://${connectionConfig.endpointURL}/rest/api/latest + connection_config: + endpointURL: + type: string + title: Domain + description: The domain of your Jira Data Center account + pattern: '^https://[a-z0-9.-]+.atlassian.net$' + example: https://foobar.atlassian.net + +jotform: + display_name: Jotform + categories: + - surveys + auth_mode: API_KEY + proxy: + base_url: https://api.jotform.com + headers: + apikey: ${apiKey} + docs: https://docs.nango.dev/integrations/all/jotform + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Jotform account + +helpscout-docs: + display_name: Help Scout Docs + auth_mode: BASIC + proxy: + retry: + after: 'x-ratelimit-reset' + base_url: https://docsapi.helpscout.net + verification: + method: GET + endpoint: /v1/sites + docs: https://docs.nango.dev/integrations/all/helpscout + docs_connect: https://docs.nango.dev/integrations/all/helpscout-docs/connect + credentials: + username: + type: string + title: API Key + description: Your Help Scout Docs API Key + secret: true + doc_section: '#step-1-finding-help-scout-api-key' + password: + type: string + title: '' + description: '' + default_value: 'X' + hidden: true + +helpscout-mailbox: + display_name: Help Scout Mailbox + auth_mode: OAUTH2 + authorization_url: https://secure.helpscout.net/authentication/authorizeClientApplication + token_url: https://api.helpscout.net/v2/oauth2/token + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + retry: + after: 'x-ratelimit-retry-after' + base_url: https://api.helpscout.net + docs: https://docs.nango.dev/integrations/all/helpscout + +keap: + display_name: Keap + categories: + - marketing + auth_mode: OAUTH2 + authorization_url: https://accounts.infusionsoft.com/app/oauth/authorize + token_url: https://api.infusionsoft.com/token + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://api.infusionsoft.com + docs: https://docs.nango.dev/integrations/all/keap + +keeper-scim: + display_name: Keeper(SCIM) + categories: + - productivity + auth_mode: API_KEY + proxy: + headers: + authorization: Bearer ${apiKey} + base_url: https://keepersecurity.com/api/rest/scim/v2/${connectionConfig.node} + verification: + method: GET + endpoint: /Users + docs: https://docs.nango.dev/integrations/all/keeper + docs_connect: https://docs.nango.dev/integrations/all/keeper/connect + credentials: + apiKey: + type: string + title: API Key + description: The API key for your node keeper account + pattern: '^[A-Za-z0-9+/=]+$' + example: 'J9b7kgdL2gf14d5F9p67zYXVrTZPTMEnl3/EmwwI9K2=' + doc_section: '#step-2-finding-your-api-key-api-token' + connection_config: + node: + type: string + title: Node + description: The node id to your Keeper account + pattern: '^\d{15}$' + example: '123435384338765' + doc_section: '#step-1-finding-your-node-id' + +klipfolio: + display_name: Klipfolio + categories: + - productivity + - dev-tools + auth_mode: API_KEY + proxy: + base_url: https://app.klipfolio.com + headers: + kf-api-key: ${apiKey} + verification: + method: GET + endpoint: /api/1.0/profile + docs: https://docs.nango.dev/integrations/all/klipfolio + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Klipfolio account + +klaviyo: + display_name: Klaviyo + categories: + - marketing + auth_mode: API_KEY + proxy: + base_url: https://a.klaviyo.com + headers: + authorization: Klaviyo-API-Key ${apiKey} + revision: '2024-07-15' + verification: + method: GET + endpoint: /api/accounts + retry: + after: 'retry-after' + docs: https://docs.nango.dev/integrations/all/klaviyo + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Klaviyo account + doc_section: '#step-1-finding-klaviyo-api-key' + +klaviyo-oauth: + display_name: Klaviyo (oauth) + categories: + - marketing + auth_mode: OAUTH2 + authorization_url: https://www.klaviyo.com/oauth/authorize + token_url: https://a.klaviyo.com/oauth/token + token_request_auth_method: basic + scope_separator: ' ' + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://a.klaviyo.com + headers: + revision: '2024-07-15' + retry: + after: 'retry-after' + docs: https://docs.nango.dev/integrations/all/klaviyo + +kustomer: + display_name: Kustomer + categories: + - crm + auth_mode: API_KEY + proxy: + base_url: https://${connectionConfig.extension}.kustomerapp.com + retry: + after: 'x-ratelimit-reset' + headers: + authorization: Bearer ${apiKey} + docs: https://docs.nango.dev/integrations/all/kustomer + connection_config: + extension: + type: string + title: Kustomer Domain + description: The subdomain of your Kustomer account + pattern: '^[a-z0-9_-]+$' + example: domain + suffix: .kustomerapp.com + prefix: https:// + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Kustomer account + +lagrowthmachine: + display_name: La Growth Machine + categories: + - marketing + auth_mode: API_KEY + proxy: + base_url: https://apiv2.lagrowthmachine.com + query: + KEY: ${apiKey} + docs: https://docs.nango.dev/integrations/all/lagrowthmachine + docs_connect: https://docs.nango.dev/integrations/all/lagrowthmachine/connect + credentials: + apiKey: + type: string + title: API Key + description: The API key for your La Growth Machine account + example: 1bc32cba-a5d6-438a-bbcc-af312f560a3c + format: uuid + doc_section: '#step-1-finding-your-api-key' + +lastpass: + display_name: LastPass + categories: + - productivity + auth_mode: BASIC + proxy: + base_url: https://lastpass.com + docs: https://docs.nango.dev/integrations/all/lastpass + docs_connect: https://docs.nango.dev/integrations/all/lastpass/connect + credentials: + username: + type: string + title: CID + description: Your LastPass Account number + doc_section: '#step-1-finding-your-cid' + password: + type: string + title: Provhash + description: 'Your LastPass API key' + secret: true + doc_section: '#step-2-generating-your-provhash' + +lattice: + display_name: Lattice + categories: + - hr + auth_mode: API_KEY + proxy: + base_url: https://api.latticehq.com/ + headers: + authorization: Bearer ${apiKey} + accept: application/json + content-type: application/json + retry: + after: 'retry-after' + docs: https://docs.nango.dev/integrations/all/lattice + docs_connect: https://docs.nango.dev/integrations/all/lattice/connect + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Lattice account + doc_section: '#step-1-finding-lattice-api-key' + +lessonly: + display_name: Lessonly + categories: + - productivity + auth_mode: BASIC + proxy: + base_url: https://api.lessonly.com/api + docs: https://docs.nango.dev/integrations/all/lessonly + credentials: + username: + type: string + title: Subdomain + description: Your Lessonly Subdomain + password: + type: string + title: API Key + description: Your Lessonly API key + secret: true + +lever: + display_name: Lever + categories: + - ats + auth_mode: OAUTH2 + authorization_url: https://auth.lever.co/authorize + token_url: https://auth.lever.co/oauth/token + authorization_params: + response_type: code + prompt: consent + audience: https://api.lever.co/v1 + proxy: + base_url: https://api.lever.co + docs: https://docs.nango.dev/integrations/all/lever + +lever-basic: + display_name: Lever (basic auth) + auth_mode: BASIC + proxy: + base_url: https://api.lever.co + docs: https://docs.nango.dev/integrations/all/lever + docs_connect: https://docs.nango.dev/integrations/all/lever-basic/connect + credentials: + username: + type: string + title: User name + description: The API Key of your lever account + doc_section: '#step-1-finding-lever-api-key' + password: + type: string + title: '' + description: '' + default_value: '' + hidden: true + +lever-sandbox: + display_name: Lever (sandbox) + auth_mode: OAUTH2 + authorization_url: https://sandbox-lever.auth0.com/authorize + token_url: https://sandbox-lever.auth0.com/oauth/token + authorization_params: + response_type: code + prompt: consent + audience: https://api.sandbox.lever.co/v1/ + proxy: + base_url: https://api.sandbox.lever.co + docs: https://docs.nango.dev/integrations/all/lever + +lever-basic-sandbox: + display_name: Lever (basic auth) (sandbox) + auth_mode: BASIC + proxy: + base_url: https://api.sandbox.lever.co + docs: https://docs.nango.dev/integrations/all/lever + credentials: + username: + type: string + title: User name + description: The API Key of your Lever sandbox account + password: + type: string + title: '' + description: '' + default_value: '' + hidden: true + +linear: + display_name: Linear + categories: + - productivity + - ticketing + auth_mode: OAUTH2 + authorization_url: https://linear.app/oauth/authorize + token_url: https://api.linear.app/oauth/token + scope_separator: ',' + authorization_params: + prompt: consent + proxy: + base_url: https://api.linear.app + retry: + at: 'x-ratelimit-requests-reset' + remaining: 'x-ratelimit-requests-remaining' + error_code: 400 + disable_pkce: true + webhook_routing_script: linearWebhookRouting + post_connection_script: linearPostConnection + webhook_user_defined_secret: true + docs: https://docs.nango.dev/integrations/all/linear + +linkedin: + display_name: LinkedIn + categories: + - ats + - social + auth_mode: OAUTH2 + authorization_url: https://www.linkedin.com/oauth/v2/authorization + token_url: https://www.linkedin.com/oauth/v2/accessToken + disable_pkce: true + proxy: + base_url: https://api.linkedin.com + docs: https://docs.nango.dev/integrations/all/linkedin + +linkhut: + display_name: LinkHut + auth_mode: OAUTH2 + authorization_url: https://ln.ht/_/oauth/authorize + token_url: https://api.ln.ht/v1/oauth/token + proxy: + base_url: https://api.ln.ht + docs: https://docs.nango.dev/integrations/all/linkhut + +loops-so: + display_name: Loops.so + categories: + - marketing + - communication + auth_mode: API_KEY + proxy: + base_url: https://app.loops.so/api + headers: + accept: application/json + authorization: Bearer ${apiKey} + verification: + method: GET + endpoint: /v1/api-key + docs: https://docs.nango.dev/integrations/all/loops-so + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Loops.so account + pattern: '^[a-f0-9]{32}$' + example: d2d561f5ff80136f69b4b5a31b9fb3c9 + +luma: + display_name: Luma + categories: + - productivity + - ticketing + auth_mode: API_KEY + proxy: + headers: + x-luma-api-key: ${apiKey} + base_url: https://api.lu.ma + verification: + method: GET + endpoint: /public/v1/user/get-self + docs: https://docs.nango.dev/integrations/all/luma + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Luma account + +listmonk: + display_name: Listmonk + categories: + - marketing + auth_mode: BASIC + proxy: + base_url: https://${connectionConfig.domain}/api + headers: + content-type: application/json + retry: + after: 'retry-after' + verification: + method: GET + endpoint: /lists + docs: https://docs.nango.dev/integrations/all/listmonk + connection_config: + domain: + type: string + title: Domain + description: The domain of your Listmonk account + format: hostname + prefix: https:// + credentials: + username: + type: string + title: API User + description: The API user to your Listmonk account + password: + type: string + title: Token + description: The token to your Listmonk account + secret: true + +make: + display_name: Make + categories: + - productivity + auth_mode: API_KEY + proxy: + base_url: https://${connectionConfig.environmentUrl}/api/v2 + headers: + authorization: Token ${apiKey} + verification: + method: GET + endpoint: /users/me + docs: https://docs.nango.dev/integrations/all/make + connection_config: + environmentUrl: + type: string + title: Domain + description: The domain of your Make account + format: hostname + prefix: https:// + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Make account + +mailgun: + display_name: Mailgun + categories: + - marketing + auth_mode: BASIC + proxy: + base_url: https://${connectionConfig.region}.mailgun.net + verification: + method: GET + endpoint: /v4/domains + docs: https://docs.nango.dev/integrations/all/mailgun + connection_config: + region: + type: string + title: Region + description: The region of your Mailgun account + pattern: '^[a-z]+$' + example: us + +mailchimp: + display_name: Mailchimp + categories: + - marketing + - surveys + auth_mode: OAUTH2 + authorization_url: https://login.mailchimp.com/oauth2/authorize + token_url: https://login.mailchimp.com/oauth2/token + authorization_params: + response_type: code + proxy: + base_url: https://${connectionConfig.dc}.api.mailchimp.com + docs: https://docs.nango.dev/integrations/all/mailchimp + connection_config: + dc: + type: string + title: Data Center + description: The data center for your account + pattern: '^[a-z]+\d*$' + example: us6 + +# Untested configuration. Please reach out if you have a test account that we can use to test it. +manatal: + display_name: Manatal + auth_mode: API_KEY + categories: + - crm + - hr + proxy: + base_url: https://api.manatal.com/open/v3 + verification: + method: GET + endpoint: /users + headers: + authorization: Token ${apiKey} + paginate: + type: link + limit_name_in_request: page_size + link_path_in_response_body: next + response_path: results + docs: https://docs.nango.dev/integrations/all/manatal + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Manatal account + +marketo: + display_name: Marketo + auth_mode: OAUTH2_CC + proxy: + base_url: https://${connectionConfig.endpointURL} + token_url: https://${connectionConfig.identityURL}/identity/oauth/token + token_params: + grant_type: client_credentials + docs: https://docs.nango.dev/integrations/all/marketo + connection_config: + endpointURL: + type: string + title: Domain + description: The domain of your Marketo account + format: hostname + example: xxx.mktorest.com + prefix: https:// + suffix: / + order: 1 + identityURL: + type: string + title: Identity URL + description: The identity URL of your Marketo account + format: hostname + prefix: https:// + example: xxx.mktorest.com + suffix: /identity/oauth/token + order: 2 + +malwarebytes: + display_name: Malwarebytes + categories: + - other + auth_mode: OAUTH2_CC + token_url: https://api.malwarebytes.com/oauth2/token + token_request_auth_method: basic + scope_separator: ' ' + token_params: + grant_type: client_credentials + proxy: + base_url: https://api.malwarebytes.com + headers: + accountid: ${connectionConfig.accountId} + connection_config: + accountId: + type: string + title: Account Id + description: Your Nebula account id + pattern: '[\da-fA-F]{8}-?[\da-fA-F]{4}-?[\da-fA-F]{4}-?[\da-fA-F]{4}-?[\da-fA-F]{12}$' + example: 9256034b-7967-4253-a5d9-260663e4fa4f + order: 1 + doc_section: '#step-1-finding-your-account-id' + + docs: https://docs.nango.dev/integrations/all/malwarebytes + docs_connect: https://docs.nango.dev/integrations/all/malwarebytes/connect + +medallia: + display_name: Medallia + categories: + - crm + - support + - surveys + auth_mode: OAUTH2_CC + token_url: https://${connectionConfig.reportingInstance}/oauth/${connectionConfig.tenantName}/token + token_request_auth_method: basic + token_params: + grant_type: client_credentials + proxy: + retry: + after: 'x-ratelimit-reset' + base_url: https://${connectionConfig.gatewayUrl}.apis.medallia.com + docs: https://docs.nango.dev/integrations/all/medallia + connection_config: + reportingInstance: + type: string + title: Domain + description: The domain of your Medallia account + format: hostname + prefix: https:// + tenantName: + type: string + title: Tenant Name + description: The tenant name of your Medallia account + gatewayUrl: + type: string + title: Gateway URL + description: The gateway URL of your Medallia account + format: hostname + prefix: https:// + +metabase: + display_name: Metabase + categories: + - analytics + auth_mode: API_KEY + proxy: + base_url: https://${connectionConfig.domain}.com + headers: + x-api-key: ${apiKey} + verification: + method: GET + endpoint: /api/database + docs: https://docs.nango.dev/integrations/all/metabase + connection_config: + domain: + type: string + title: Metabase Domain + description: The domain (without the extension) of your Metabase account + pattern: '^[a-z0-9.-]+$' + example: metabase + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Metabase account + +microsoft: + display_name: Microsoft + auth_mode: OAUTH2 + authorization_url: https://login.microsoftonline.com/common/oauth2/v2.0/authorize + token_url: https://login.microsoftonline.com/common/oauth2/v2.0/token + disable_pkce: true + default_scopes: + - offline_access + authorization_params: + response_type: code + response_mode: query + prompt: consent + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://graph.microsoft.com + retry: + after: 'retry-after' + decompress: true + docs: https://docs.nango.dev/integrations/all/microsoft + +microsoft-teams: + display_name: Microsoft Teams + categories: + - productivity + - video + alias: microsoft + webhook_routing_script: microsoftTeamsWebhookRouting + post_connection_script: microsoftTeamsPostConnection + docs: https://docs.nango.dev/integrations/all/microsoft-teams + +microsoft-tenant-specific: + display_name: Microsoft (tenant) + categories: + - erp + auth_mode: OAUTH2 + authorization_url: https://login.microsoftonline.com/${connectionConfig.tenant}/oauth2/v2.0/authorize + token_url: https://login.microsoftonline.com/${connectionConfig.tenant}/oauth2/v2.0/token + disable_pkce: true + default_scopes: + - offline_access + authorization_params: + response_type: code + response_mode: query + prompt: consent + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://graph.microsoft.com + docs: https://docs.nango.dev/integrations/all/microsoft-tenant-specific + connection_config: + tenant: + type: string + title: Tenant + description: The tenant of your Microsoft account + +microsoft-business-central: + display_name: Microsoft Business Central + categories: + - erp + auth_mode: OAUTH2_CC + token_url: https://login.microsoftonline.com/${connectionConfig.tenantId}/oauth2/v2.0/token + token_params: + grant_type: client_credentials + proxy: + base_url: https://api.businesscentral.dynamics.com/v2.0/${connectionConfig.tenantId}/${connectionConfig.environmentName} + docs: https://docs.nango.dev/integrations/all/microsoft-business-central + docs_connect: https://docs.nango.dev/integrations/all/microsoft-business-central/connect + connection_config: + tenantId: + type: string + title: Tenant ID + description: The unique identifier for your organization that uses Microsoft services + format: uuid + example: a1b2c3d4-e5f6-47a8-9b0c-d1234567890f + doc_section: '#step-1-finding-your-tenant-id' + order: 1 + environmentName: + type: string + title: Enrivonment Name + description: The environment name to your organization + example: production + pattern: '^[a-zA-Z0-9-_]+$' + doc_section: '#step-2-finding-your-enrivonment-name' + order: 2 + +microsoft-ads: + display_name: Microsoft Ads + alias: microsoft + categories: + - marketing + default_scopes: + - https://ads.microsoft.com/msads.manage + - offline_access + proxy: + base_url: https://clientcenter.api.bingads.microsoft.com/Api + refresh_params: + grant_type: refresh_token + scope: https://ads.microsoft.com/msads.manage + docs: https://docs.nango.dev/integrations/all/microsoft-ads + +microsoft-entra-id: + display_name: Microsoft Entra ID + categories: + - other + alias: microsoft + docs: https://docs.nango.dev/integrations/all/microsoft-entra-id + +microsoft-power-bi: + display_name: Microsoft Power BI + categories: + - productivity + alias: microsoft + proxy: + base_url: https://api.powerbi.com + docs: https://docs.nango.dev/integrations/all/microsoft-power-bi + +mindbody: + display_name: Mindbody (api key) + categories: + - productivity + auth_mode: API_KEY + proxy: + base_url: https://api.mindbodyonline.com + headers: + api-key: ${apiKey} + siteid: ${connectionConfig.siteId} + authorization: ${connectionConfig.staffUserToken} + verification: + method: GET + endpoint: /public/v6/site/locations + docs: https://docs.nango.dev/integrations/all/mindbody + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Mindbody account + pattern: '^[a-f0-9]{32}$' + example: a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4 + connection_config: + siteId: + type: string + title: Site ID + description: The site ID for your Mindbody account + pattern: '^\d+$' + example: '-99' + staffUserToken: + type: string + title: Staff User Token + description: The staff user token for your Mindbody account + pattern: '^[a-f0-9]{32}$' + example: a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4 + +mixpanel: + display_name: Mixpanel + categories: + - analytics + auth_mode: BASIC + proxy: + base_url: https://mixpanel.com + credentials: + # https://developer.mixpanel.com/reference/service-accounts + username: + type: string + title: Service Account Username + description: Mixpanel Service Account Username + doc_section: '#step-1-finding-mixpanel-api-key' + password: + type: string + title: Service Account Secret + description: Mixpanel Service Account Secret + doc_section: '#step-1-finding-mixpanel-api-key' + docs: https://docs.nango.dev/integrations/all/mixpanel + docs_connect: https://docs.nango.dev/integrations/all/mixpanel/connect + +miro: + display_name: Miro + categories: + - design + - productivity + auth_mode: OAUTH2 + authorization_url: https://miro.com/oauth/authorize + token_url: https://api.miro.com/v1/oauth/token + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://api.miro.com + docs: https://docs.nango.dev/integrations/all/miro + +miro-scim: + display_name: Miro (SCIM API) + categories: + - design + - productivity + auth_mode: API_KEY + proxy: + base_url: https://miro.com/api + verification: + method: GET + endpoint: /v1/scim/Users + headers: + authorization: Bearer ${apiKey} + docs: https://docs.nango.dev/integrations/all/miro + docs_connect: https://docs.nango.dev/integrations/all/miro-scim/connect + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Miro scim account + doc_section: '#step-1-finding-miro-api-key' + +monday: + display_name: Monday + categories: + - productivity + - ticketing + auth_mode: OAUTH2 + authorization_url: https://auth.monday.com/oauth2/authorize + token_url: https://auth.monday.com/oauth2/token + proxy: + base_url: https://api.monday.com + docs: https://docs.nango.dev/integrations/all/monday + +mural: + display_name: Mural + categories: + - design + auth_mode: OAUTH2 + authorization_url: https://app.mural.co/api/public/v1/authorization/oauth2 + token_url: https://app.mural.co/api/public/v1/authorization/oauth2/token + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://app.mural.co + docs: https://docs.nango.dev/integrations/all/mural + +nationbuilder: + display_name: NationBuilder + auth_mode: OAUTH2 + authorization_url: https://${connectionConfig.accountId}.nationbuilder.com/oauth/authorize + token_url: https://${connectionConfig.accountId}.nationbuilder.com/oauth/token + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + default_scopes: + - default + docs: https://docs.nango.dev/integrations/all/nationbuilder + proxy: + base_url: https://${connectionConfig.accountId}.nationbuilder.com/api + connection_config: + accountId: + type: string + title: Account ID + description: The account ID of your NationBuilder account + +netsuite: + display_name: NetSuite + categories: + - accounting + - erp + auth_mode: OAUTH2 + authorization_url: https://${connectionConfig.accountId}.app.netsuite.com/app/login/oauth2/authorize.nl + authorization_params: + prompt: consent + token_url: https://${connectionConfig.accountId}.suitetalk.api.netsuite.com/services/rest/auth/oauth2/v1/token + default_scopes: + - rest_webservices + proxy: + base_url: https://${connectionConfig.accountId}.suitetalk.api.netsuite.com/services/rest/record/v1 + retry: + after: 'retry-after' + docs: https://docs.nango.dev/integrations/all/netsuite + connection_config: + accountId: + type: string + title: Account ID + description: The account ID of your NetSuite account + pattern: '^[a-zA-Z0-9-_]+$' + example: tstdrv231585 + +netsuite-tba: + alias: netsuite + display_name: NetSuite (tba) + auth_mode: TBA + docs: https://docs.nango.dev/integrations/all/netsuite + +next-cloud-ocs: + display_name: Next Cloud OCS + auth_mode: BASIC + proxy: + base_url: https://${connectionConfig.domain}/ocs/v1.php + headers: + 'ocs-apirequest': 'true' + docs: http://docs.nango.dev/integrations/all/next-cloud + connection_config: + domain: + type: string + title: Domain + description: The domain of your Next Cloud account + format: hostname + prefix: https:// + +notion: + display_name: Notion + categories: + - knowledge-base + - productivity + auth_mode: OAUTH2 + authorization_url: https://api.notion.com/v1/oauth/authorize + token_url: https://api.notion.com/v1/oauth/token + authorization_params: + response_type: code + owner: user + authorization_method: header + body_format: json + proxy: + retry: + after: 'retry-after' + base_url: https://api.notion.com + headers: + 'notion-version': '2022-06-28' + paginate: + type: cursor + cursor_path_in_response: next_cursor + cursor_name_in_request: start_cursor + limit_name_in_request: page_size + response_path: results + docs: https://docs.nango.dev/integrations/all/notion + +notion-scim: + display_name: Notion (SCIM API) + categories: + - knowledge-base + - productivity + auth_mode: API_KEY + proxy: + base_url: https://api.notion.com/scim + verification: + method: GET + endpoint: /v2/Users + headers: + authorization: Bearer ${apiKey} + docs: https://docs.nango.dev/integrations/all/notion + docs_connect: https://docs.nango.dev/integrations/all/notion-scim/connect + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Notion scim account + doc_section: '#step-1-finding-your-scim-api-key-token' + +odoo: + display_name: Odoo + categories: + - erp + auth_mode: OAUTH2 + authorization_url: https://${connectionConfig.serverUrl}/restapi/1.0/common/oauth2/authorize + token_url: https://${connectionConfig.serverUrl}/restapi/1.0/common/oauth2/access_token + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://${connectionConfig.serverUrl} + docs: https://docs.nango.dev/integrations/all/odoo + connection_config: + serverUrl: + type: string + title: Domain + description: The domain of your Odoo account + format: hostname + prefix: https:// + +okta: + display_name: Okta + auth_mode: OAUTH2 + authorization_url: https://${connectionConfig.subdomain}.okta.com/oauth2/v1/authorize + token_url: https://${connectionConfig.subdomain}.okta.com/oauth2/v1/token + authorization_params: + response_type: code + response_mode: query + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://${connectionConfig.subdomain}.okta.com + retry: + at: 'x-rate-limit-reset' + paginate: + type: 'link' + limit_name_in_request: 'limit' + link_rel_in_response_header: 'next' + docs: https://docs.nango.dev/integrations/all/okta + connection_config: + subdomain: + type: string + title: Okta Domain + description: The subdomain of your Okta account + pattern: '^[a-z0-9_-]+$' + example: domain + suffix: .okta.com + prefix: https:// + +okta-preview: + alias: okta + display_name: Okta (Preview) + authorization_url: https://${connectionConfig.subdomain}.oktapreview.com/oauth2/v1/authorize + token_url: https://${connectionConfig.subdomain}.oktapreview.com/oauth2/v1/token + proxy: + base_url: https://${connectionConfig.subdomain}.oktapreview.com + docs: https://docs.nango.dev/integrations/all/okta + connection_config: + subdomain: + type: string + title: Okta Preview Domain + description: The subdomain of your Okta Preview account + pattern: '^[a-z0-9_-]+$' + example: domain + suffix: .oktapreview.com + prefix: https:// + +one-drive: + display_name: One Drive + categories: + - knowledge-base + - storage + alias: microsoft + docs: https://docs.nango.dev/integrations/all/one-drive + +one-note: + display_name: One Note + categories: + - productivity + alias: microsoft + docs: https://docs.nango.dev/integrations/all/one-note + +openai: + display_name: OpenAI + categories: + - productivity + - dev-tools + auth_mode: API_KEY + proxy: + base_url: https://api.openai.com + headers: + authorization: Bearer ${apiKey} + content-type: application/json + verification: + method: GET + endpoint: /v1/models + retry: + after: 'x-ratelimit-reset-requests' + docs: https://docs.nango.dev/integrations/all/openai + credentials: + apiKey: + type: string + title: API Key + description: The API key for your OpenAI account + +ory: + display_name: Ory + categories: + - other + auth_mode: OAUTH2_CC + proxy: + base_url: https://${connectionConfig.projectSlug}.projects.oryapis.com + token_url: https://${connectionConfig.projectSlug}.projects.oryapis.com/oauth2/token + scope_separator: ' ' + token_params: + grant_type: client_credentials + docs: https://docs.nango.dev/integrations/all/ory + connection_config: + projectSlug: + type: string + title: Project Slug + description: The project slug of your Ory project + +osu: + display_name: Osu + categories: + - gaming + auth_mode: OAUTH2 + authorization_url: https://osu.ppy.sh/oauth/authorize + token_url: https://osu.ppy.sh/oauth/token + default_scopes: + - identify + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://osu.ppy.sh + docs: https://docs.nango.dev/integrations/all/osu + +oura: + display_name: Oura + categories: + - sports + auth_mode: OAUTH2 + authorization_url: https://cloud.ouraring.com/oauth/authorize + token_url: https://api.ouraring.com/oauth/token + scope_separator: ' ' + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://api.ouraring.com + docs: https://docs.nango.dev/integrations/all/oura + +outlook: + display_name: Outlook + categories: + - communication + alias: microsoft + docs: https://docs.nango.dev/integrations/all/outlook + +outreach: + display_name: Outreach + categories: + - marketing + auth_mode: OAUTH2 + authorization_url: https://api.outreach.io/oauth/authorize + token_url: https://api.outreach.io/oauth/token + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://api.outreach.io + docs: https://docs.nango.dev/integrations/all/outreach + +pagerduty: + display_name: PagerDuty + categories: + - dev-tools + auth_mode: OAUTH2 + authorization_url: https://app.pagerduty.com/oauth/authorize + token_url: https://app.pagerduty.com/oauth/token + proxy: + base_url: https://api.pagerduty.com + docs: https://docs.nango.dev/integrations/all/pagerduty + +pandadoc: + display_name: Pandadoc + categories: + - legal + auth_mode: OAUTH2 + authorization_url: https://app.pandadoc.com/oauth2/authorize + token_url: https://api.pandadoc.com/oauth2/access_token + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://api.pandadoc.com + docs: https://docs.nango.dev/integrations/all/pandadoc + +payfit: + display_name: Payfit + categories: + - hr + auth_mode: OAUTH2 + authorization_url: https://oauth.payfit.com/authorize + token_url: https://app.pagerduty.com/oauth/token + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + proxy: + base_url: https://partner-api.payfit.com + docs: https://docs.nango.dev/integrations/all/payfit + +paypal: + display_name: Paypal + categories: + - payment + auth_mode: OAUTH2 + authorization_url: https://www.paypal.com/signin/authorize + token_url: https://api.paypal.com/v1/oauth2/token + token_request_auth_method: basic + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://api-m.paypal.com + docs: https://docs.nango.dev/integrations/all/paypal + +paypal-sandbox: + display_name: Paypal (sandbox) + auth_mode: OAUTH2 + authorization_url: https://www.sandbox.paypal.com/signin/authorize + token_url: https://api-m.sandbox.paypal.com/v1/oauth2/token + token_request_auth_method: basic + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://api-m.sandbox.paypal.com + docs: https://docs.nango.dev/integrations/all/paypal + +pendo: + display_name: Pendo + categories: + - analytics + auth_mode: API_KEY + proxy: + base_url: https://app.pendo.io + verification: + method: GET + endpoint: /api/v1/page + headers: + x-pendo-integration-key: ${apiKey} + docs: https://docs.nango.dev/integrations/all/pendo + docs_connect: https://docs.nango.dev/integrations/all/pendo/connect + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Pendo account + doc_section: '#step-1-finding-pendo-api-key' + +pennylane: + display_name: Pennylane + categories: + - accounting + - banking + - invoicing + - payment + auth_mode: OAUTH2 + authorization_url: https://app.pennylane.com/oauth/authorize + token_url: https://app.pennylane.com/oauth/token + proxy: + base_url: https://app.pennylane.com + scope_separator: '+' + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + authorization_url_skip_encode: + - scopes + docs: https://docs.nango.dev/integrations/all/pennylane + +peopledatalabs: + display_name: People Data Labs + categories: + - analytics + auth_mode: API_KEY + proxy: + base_url: https://api.peopledatalabs.com + query: + api_key: ${apiKey} + docs: https://docs.nango.dev/integrations/all/peopledatalabs + credentials: + apiKey: + type: string + title: API Key + description: The API key for your People Data Labs account + +perplexity: + display_name: Perplexity + categories: + - productivity + - dev-tools + auth_mode: API_KEY + proxy: + headers: + authorization: Bearer ${apiKey} + base_url: https://api.perplexity.ai + docs: https://docs.nango.dev/integrations/all/perplexity + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Perplexity account + pattern: '^pplx-[a-f0-9]+$' + example: pplx-xxxxxx + +perimeter81: + display_name: Perimeter81 + categories: + - productivity + auth_mode: TWO_STEP + proxy: + base_url: https://api.perimeter81.com/api/rest + token_url: https://api.${connectionConfig.domain}.com/api/v1/auth/authorize + token_params: + apiKey: ${credential.apiKey} + grantType: api_key + token_headers: + content-type: application/json + token_response: + token: data.accessToken + token_expiration: data.accessTokenExpire + token_expiration_strategy: expireAt + docs: https://docs.nango.dev/integrations/all/perimeter81 + docs_connect: https://docs.nango.dev/integrations/all/perimeter81/connect + connection_config: + domain: + type: string + title: Domain + description: The domain for Perimeter81 + pattern: '^(perimeter81|eu\.sase\.checkpoint)$' + example: '(perimeter81,eu.sase.checkpoint)' + doc_section: '#step-1-finding-your-perimeter81-domain-and-perimeter81-api-key' + suffix: .com + prefix: https://api. + order: 1 + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Perimeter81 account + secret: true + +personio: + display_name: Personio + categories: + - hr + auth_mode: OAUTH2_CC + proxy: + base_url: https://api.personio.de/v1 + headers: + x-personio-partner-id: ${connectionConfig.partnerId} + x-personio-app-id: ${connectionConfig.appId} + token_url: https://api.personio.de/v1/auth + body_format: json + docs: https://docs.nango.dev/integrations/all/personio + docs_connect: https://docs.nango.dev/integrations/all/personio/connect + connection_config: + partnerId: + type: string + title: Partner ID + description: The partner ID of your Personio account + doc_section: '#step-1-finding-personio-client-id' + appId: + type: string + title: App ID + description: The app ID of your Personio account + doc_section: '#step-2-finding-personio-client-secret' + +personio-v2: + display_name: Personio (v2) + categories: + - hr + auth_mode: OAUTH2_CC + proxy: + base_url: https://api.personio.de/v2 + headers: + content-type: application/x-www-form-urlencoded + token_url: https://api.personio.de/v2/auth/token + scope_separator: ' ' + docs: https://docs.nango.dev/integrations/all/personio + token_params: + grant_type: client_credentials + +personio-recruiting: + display_name: Personio Recruiting + categories: + - hr + auth_mode: API_KEY + proxy: + base_url: https://api.personio.de/v1 + headers: + authorization: Bearer ${apiKey} + x-company-id: ${connectionConfig.companyId} + x-personio-partner-id: ${connectionConfig.partnerId} + x-personio-app-id: ${connectionConfig.appId} + verification: + method: GET + endpoint: /xml?language=en + base_url_override: https://${connectionConfig.company}.jobs.personio.de + headers: + accept: application/xml + content-type: xml + docs: https://docs.nango.dev/integrations/all/personio + connection_config: + companyId: + type: string + title: Company ID + description: The company ID of your Personio account + company: + type: string + title: Company Name + description: The company name of your Personio account + partnerId: + type: string + title: Partner ID + description: The partner ID of your Personio account + appId: + type: string + title: App ID + description: The app ID of your Personio account + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Pingboard account + +pingboard: + display_name: Pingboard + categories: + - productivity + auth_mode: OAUTH2_CC + proxy: + base_url: https://app.pingboard.com/api/v2 + token_url: https://app.pingboard.com/oauth/token + scope_separator: ' ' + token_params: + grant_type: client_credentials + docs: https://docs.nango.dev/integrations/all/pingboard + +pinterest: + display_name: Pinterest + categories: + - design + - marketing + - social + - video + auth_mode: OAUTH2 + authorization_url: https://www.pinterest.com/oauth + token_url: https://api.pinterest.com/v5/oauth/token + token_request_auth_method: basic + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://api.pinterest.com + docs: https://docs.nango.dev/integrations/all/pinterest + +pipedrive: + display_name: Pipedrive + categories: + - crm + auth_mode: OAUTH2 + authorization_url: https://oauth.pipedrive.com/oauth/authorize + token_url: https://oauth.pipedrive.com/oauth/token + token_response_metadata: + - api_domain + proxy: + base_url: ${connectionConfig.api_domain}/api + decompress: true + paginate: + type: offset + offset_name_in_request: start + response_path: data + limit_name_in_request: limit + docs: https://docs.nango.dev/integrations/all/pipedrive + connection_config: + api_domain: + type: string + title: API URL + description: The API URL of your Pipedrive account + format: uri + pattern: '^https?://.*$' + +pivotaltracker: + display_name: Pivotal Tracker + categories: + - productivity + auth_mode: API_KEY + proxy: + headers: + x-trackertoken: ${apiKey} + base_url: https://www.pivotaltracker.com/services/v5 + verification: + method: GET + endpoint: /accounts + docs: https://docs.nango.dev/integrations/all/pivotaltracker + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Pivotal Tracker account + +plain: + display_name: Plain + categories: + - support + auth_mode: API_KEY + proxy: + headers: + authorization: Bearer ${apiKey} + base_url: https://core-api.uk.plain.com/graphql/v1 + verification: + method: GET + endpoint: ?query=%7B__schema%7Btypes%7Bname,kind,fields%7Bname%7D%7D%7D%7D + docs: https://docs.nango.dev/integrations/all/plain + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Plain account + +podium: + display_name: Podium + categories: + - communication + - marketing + auth_mode: OAUTH2 + authorization_url: https://api.podium.com/oauth/authorize + token_url: https://api.podium.com/oauth/token + scope_separator: ' ' + body_format: json + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + headers: + podium-version: ${connectionConfig.apiVersion} + content-type: application/json + base_url: https://api.podium.com + retry: + after: 'x-ratelimit-reset' + docs: https://docs.nango.dev/integrations/all/podium + connection_config: + apiVersion: + type: string + title: API Version + description: The API version of your Podium account + +posthog: + display_name: PostHog + categories: + - dev-tools + auth_mode: API_KEY + proxy: + headers: + authorization: Bearer ${apiKey} + base_url: https://${connectionConfig.subdomain}.posthog.com + verification: + method: GET + endpoint: /api/users/@me + docs: https://docs.nango.dev/integrations/all/posthog + docs_connect: https://docs.nango.dev/integrations/all/posthog/connect + connection_config: + subdomain: + type: string + title: PostHog Domain + description: The subdomain of your PostHog account + pattern: '^[a-z0-9_-]+$' + example: domain + suffix: .posthog.com + prefix: https:// + credentials: + apiKey: + type: string + title: API Key + description: The API key for your PostHog account + doc_section: '#step-1-finding-your-posthog-api-key' + +productboard: + display_name: Productboard + categories: + - productivity + auth_mode: OAUTH2 + authorization_url: https://app.productboard.com/oauth2/authorize + token_url: https://app.productboard.com/oauth2/token + scope_separator: ' ' + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + headers: + x-version: '1' + base_url: https://api.productboard.com + docs: https://docs.nango.dev/integrations/all/productboard + +qualtrics: + display_name: Qualtrics + categories: + - surveys + auth_mode: OAUTH2 + authorization_url: https://${connectionConfig.subdomain}.qualtrics.com/oauth2/auth + token_url: https://${connectionConfig.subdomain}.qualtrics.com/oauth2/token + proxy: + base_url: https://${connectionConfig.subdomain}.qualtrics.com + docs: https://docs.nango.dev/integrations/all/qualtrics + connection_config: + subdomain: + type: string + title: Qualtrics Domain + description: The subdomain of your Qualtrics account + pattern: '^[a-z0-9_-]+$' + example: domain + suffix: .qualtrics.com + prefix: https:// + +quickbooks: + display_name: Quickbooks + categories: + - accounting + auth_mode: OAUTH2 + authorization_url: https://appcenter.intuit.com/connect/oauth2 + token_url: https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer + redirect_uri_metadata: + - realmId + proxy: + connection_config: + realmId: ${connectionConfig.realmId} + base_url: https://quickbooks.api.intuit.com + docs: https://docs.nango.dev/integrations/all/quickbooks + docs_connect: https://docs.nango.dev/integrations/all/quickbooks/connect + connection_config: + realmId: + type: string + title: Quickbooks Realm ID + optional: true + description: The realmId of your quickbooks company + pattern: '^\d{16}$' + example: '9341453474484455' + doc_section: '#step-1-finding-your-realm-id' + +quickbooks-sandbox: + alias: quickbooks + display_name: Quickbooks (sandbox) + proxy: + connection_config: + realmId: ${connectionConfig.realmId} + base_url: https://sandbox-quickbooks.api.intuit.com + docs: https://docs.nango.dev/integrations/all/quickbooks + docs_connect: https://docs.nango.dev/integrations/all/quickbooks-sandbox/connect + connection_config: + realmId: + type: string + title: Quickbooks Realm ID + optional: true + description: The realmId of your quickbooks sandbox company + pattern: '^\d{16}$' + example: '9341453474484455' + doc_section: '#step-1-finding-your-realm-id' + +ragieai: + display_name: Ragie AI + categories: + - dev-tools + auth_mode: API_KEY + proxy: + base_url: https://api.ragie.ai + headers: + authorization: Bearer ${apiKey} + verification: + method: GET + endpoint: /documents + docs: https://docs.nango.dev/integrations/all/ragieai + credentials: + apiKey: + type: string + title: API Key + description: The API key for your ragie.ai account + example: tnt_IZ56tqGVgX9_k8CKnxQ9MvQgzDXcDGgtcjXABkwusxSOR8QzwxxeA1B + pattern: '^tnt_[a-zA-Z0-9_]+$' + +ramp: + display_name: Ramp + categories: + - banking + auth_mode: OAUTH2 + authorization_url: https://app.ramp.com/v1/authorize + token_url: https://api.ramp.com/developer/v1/token + authorization_method: header + proxy: + base_url: https://api.ramp.com + docs: https://docs.nango.dev/integrations/all/ramp + +ramp-sandbox: + display_name: Ramp (sandbox) + auth_mode: OAUTH2 + authorization_url: https://demo.ramp.com/v1/authorize + token_url: https://demo-api.ramp.com/developer/v1/token + authorization_method: header + proxy: + base_url: https://demo-api.ramp.com + docs: https://docs.nango.dev/integrations/all/ramp + +rapidapi: + display_name: RapidAPI + categories: + - dev-tools + auth_mode: API_KEY + proxy: + headers: + x-rapidapi-key: ${apiKey} + x-rapidapi-host: ${connectionConfig.subdomain}.p.rapidapi.com + base_url: https://${connectionConfig.subdomain}.p.rapidapi.com + docs: https://docs.nango.dev/integrations/all/rapidapi + credentials: + apiKey: + type: string + title: API Key + description: The API key for your RapidAPI account + example: b7c156af2dmgh5c635305f3744bap168553jsp75193c8367ef + pattern: '^[a-zA-Z0-9]+$' + connection_config: + subdomain: + type: string + title: Subdomain + description: The subdomain of the Rapid API. + pattern: '^[a-z0-9_-]+$' + example: api-football-v1 + suffix: .p.rapidapi.com + prefix: https:// + +reddit: + display_name: Reddit + categories: + - social + auth_mode: OAUTH2 + authorization_url: https://www.reddit.com/api/v1/authorize + token_url: https://www.reddit.com/api/v1/access_token + authorization_method: header + authorization_params: + duration: permanent + proxy: + base_url: https://oauth.reddit.com + docs: https://docs.nango.dev/integrations/all/reddit + +refiner: + display_name: Refiner + categories: + - surveys + auth_mode: API_KEY + proxy: + headers: + authorization: Bearer ${apiKey} + base_url: https://api.refiner.io/v1 + verification: + method: GET + endpoint: /account + docs: https://docs.nango.dev/integrations/all/refiner + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Refiner account + +replicate: + display_name: Replicate + auth_mode: API_KEY + proxy: + headers: + authorization: Bearer ${apiKey} + base_url: https://api.replicate.com + verification: + method: GET + endpoint: /v1/account + docs: https://docs.nango.dev/integrations/all/replicate + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Replicate account + +ring-central: + display_name: RingCentral + categories: + - support + auth_mode: OAUTH2 + authorization_url: https://platform.ringcentral.com/restapi/oauth/authorize + token_url: https://platform.ringcentral.com/restapi/oauth/token + authorization_method: header + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://platform.ringcentral.com + docs: https://docs.nango.dev/integrations/all/ring-central + +ring-central-sandbox: + display_name: RingCentral (sandbox) + auth_mode: OAUTH2 + authorization_url: https://platform.devtest.ringcentral.com/restapi/oauth/authorize + token_url: https://platform.devtest.ringcentral.com/restapi/oauth/token + authorization_method: header + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://platform.devtest.ringcentral.com + docs: https://docs.nango.dev/integrations/all/ring-central + +segment: + display_name: Segment + categories: + - analytics + - marketing + auth_mode: OAUTH2 + authorization_url: https://id.segmentapis.com/oauth2/auth + token_url: https://id.segmentapis.com/oauth2/token + token_request_auth_method: basic + proxy: + base_url: https://api.segment.io + docs: https://docs.nango.dev/integrations/all/segment + +sage: + display_name: Sage + categories: + - accounting + - erp + auth_mode: OAUTH2 + authorization_url: https://www.sageone.com/oauth2/auth/central + token_url: https://oauth.accounting.sage.com/token + authorization_params: + filter: apiv3.1 + proxy: + base_url: https://api.accounting.sage.com + docs: https://docs.nango.dev/integrations/all/sage + +sage-intacct: + display_name: Sage Intacct + categories: + - accounting + - erp + auth_mode: TWO_STEP + proxy: + base_url: https://api.intacct.com/ia/xml/xmlgw.phtml + token_url: https://api.intacct.com/ia/xml/xmlgw.phtml + body_format: xml + token_params: + request: + control: + senderid: ${credential.senderId} + password: ${credential.senderPassword} + controlid: ${now} + uniqueid: false + dtdversion: '3.0' + includewhitespace: false + operation: + authentication: + login: + userid: ${credential.userId} + companyid: ${credential.companyId} + password: ${credential.userPassword} + content: + function: + $controlid: '{{$guid}}' + getAPISession: '' + token_headers: + content-type: application/xml + token_response: + token: response.operation.result.data.api.sessionid + token_expiration: response.operation.authentication.sessiontimeout + token_expiration_strategy: expireAt + docs: https://docs.nango.dev/integrations/all/sage + docs_connect: https://docs.nango.dev/integrations/all/sage-intacct/connect + credentials: + senderId: + type: string + title: Sender ID + description: Your Sage Intacct Sender ID + doc_section: '#step-1-how-to-retrieve-the-sender-id' + senderPassword: + type: string + title: Sender Password + description: Your Sage Intacct Sender Password + secret: true + userId: + type: string + title: User ID + description: Your Sage Intacct User ID + doc_section: '#step-2-how-to-retrieve-the-user-id' + companyId: + type: string + title: Company ID + description: Your Sage Intacct Company ID + doc_section: '#step-3-how-to-retrieve-the-company-id' + userPassword: + type: string + title: User Password + description: Your Sage Intacct User Password + secret: true + +salesforce: + display_name: Salesforce + categories: + - crm + auth_mode: OAUTH2 + authorization_url: https://login.salesforce.com/services/oauth2/authorize + token_url: https://login.salesforce.com/services/oauth2/token + authorization_params: + prompt: consent + default_scopes: + - offline_access + token_response_metadata: + - instance_url + proxy: + base_url: ${connectionConfig.instance_url} + webhook_routing_script: salesforceWebhookRouting + post_connection_script: salesforcePostConnection + docs: https://docs.nango.dev/integrations/all/salesforce + connection_config: + instance_url: + type: string + title: Instance URL + description: The instance URL of your Salesforce account + format: uri + pattern: '^https?://.*$' + automated: true + +salesforce-sandbox: + display_name: Salesforce (sandbox) + auth_mode: OAUTH2 + authorization_url: https://test.salesforce.com/services/oauth2/authorize + token_url: https://test.salesforce.com/services/oauth2/token + default_scopes: + - offline_access + token_response_metadata: + - instance_url + proxy: + base_url: ${connectionConfig.instance_url} + docs: https://docs.nango.dev/integrations/all/salesforce + connection_config: + instance_url: + type: string + title: Instance URL + description: The instance URL of your Salesforce account + format: uri + pattern: '^https?://.*$' + automated: true + +salesforce-experience-cloud: + display_name: Salesforce Experience Cloud + auth_mode: OAUTH2 + authorization_url: https://${connectionConfig.subdomain}.my.site.com/services/oauth2/authorize + token_url: https://${connectionConfig.subdomain}.my.site.com/services/oauth2/token + default_scopes: + - offline_access + token_response_metadata: + - instance_url + proxy: + base_url: ${connectionConfig.instance_url} + docs: https://docs.nango.dev/integrations/all/salesforce-experience-cloud + connection_config: + subdomain: + type: string + title: Salesforce Domain + description: The subdomain of your Salesforce Experience Cloud account + pattern: '^[a-z0-9_-]+$' + example: domain + suffix: .my.site.com + prefix: https:// + instance_url: + type: string + title: Instance URL + description: The instance URL of your Salesforce Experience Cloud account + format: uri + pattern: '^https?://.*$' + automated: true +sap-success-factors: + display_name: SAP SuccessFactors + categories: + - hr + auth_mode: TWO_STEP + token_url: https://${connectionConfig.apiServer}/oauth/token + token_params: + company_id: ${connectionConfig.companyId} + client_id: ${credential.apiKey} + grant_type: urn:ietf:params:oauth:grant-type:saml2-bearer + assertion: ${credential.assertion} + token_headers: + content-type: application/x-www-form-urlencoded + proxy: + base_url: https://${connectionConfig.apiServer} + token_response: + token: access_token + token_expiration: expires_in + token_expiration_strategy: expireIn + docs: https://docs.nango.dev/integrations/all/sap-success-factors + docs_connect: https://docs.nango.dev/integrations/all/sap-success-factors/connect + connection_config: + apiServer: + type: string + title: API Server + description: The API Server to connect to your SAP SuccessFactors account + pattern: '^[a-z0-9.-]+$' + example: api41preview.sapsf.com + prefix: https:// + doc_section: '#step-1-finding-your-api-server' + order: 1 + companyId: + type: string + title: Company ID + description: The company ID of your SAP SuccessFactors account + example: SFSALES012345 + pattern: '^[A-Z0-9]+$' + doc_section: '#step-2-finding-your-company-id' + order: 2 + credentials: + apiKey: + type: string + title: API Key + description: The API key for your SAP SuccessFactors account + secret: true + doc_section: '#step-3-generating-your-api-key' + assertion: + type: string + title: SAML Assertion + description: The SAML Assertion generated for your SAP SuccessFactors account + secret: true + doc_section: '#step-4-generating-your-saml-assertion' + +scrapedo: + display_name: Scrape.do + categories: + - other + auth_mode: API_KEY + proxy: + base_url: https://api.scrape.do + query: + token: ${apiKey} + docs: https://docs.nango.dev/integrations/all/scrapedo + docs_connect: https://docs.nango.dev/integrations/all/scrapedo/connect + credentials: + apiKey: + type: string + title: API Token + description: The API Token for your Scrape.do account + example: 3c12d71308a346c41d10b19a2b2ac1ea5cacb53588d + pattern: '^[a-zA-Z0-9]+$' + doc_section: '#step-1-finding-your-api-key' + +salesloft: + display_name: Salesloft + categories: + - marketing + auth_mode: OAUTH2 + authorization_url: https://accounts.salesloft.com/oauth/authorize + token_url: https://accounts.salesloft.com/oauth/token + proxy: + base_url: https://api.salesloft.com + docs: https://docs.nango.dev/integrations/all/salesloft + +sendgrid: + display_name: SendGrid + categories: + - marketing + auth_mode: API_KEY + proxy: + headers: + authorization: Bearer ${apiKey} + base_url: https://api.sendgrid.com + docs: https://docs.nango.dev/integrations/all/sendgrid + docs_connect: https://docs.nango.dev/integrations/all/sendgrid/connect + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Sendgrid account + doc_section: '#step-1-generating-your-sendgrid-api-key' + +sedna: + display_name: Sedna (Oauth2) + auth_mode: OAUTH2_CC + categories: + - communication + proxy: + base_url: https://${connectionConfig.tenant}.sednanetwork.com/platform + token_url: https://${connectionConfig.tenant}.sednanetwork.com/platform/oauth/token + token_params: + grant_type: client_credentials + scope_separator: ',' + docs: https://docs.nango.dev/integrations/all/sedna + connection_config: + tenant: + type: string + title: Tenant + description: The tenant name to your sedna account + +sedna-basic: + display_name: Sedna (Basic Auth) + auth_mode: BASIC + categories: + - communication + proxy: + base_url: https://${connectionConfig.tenant}.sednanetwork.com/platform + docs: https://docs.nango.dev/integrations/all/sedna + connection_config: + tenant: + type: string + title: Tenant + description: The tenant name to your sedna account + +servicem8: + display_name: ServiceM8 + categories: + - productivity + auth_mode: OAUTH2 + authorization_url: https://go.servicem8.com/oauth/authorize + token_url: https://go.servicem8.com/oauth/access_token + proxy: + base_url: https://api.servicem8.com + scope_separator: ' ' + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + docs: https://docs.nango.dev/integrations/all/servicem8 + +signnow: + display_name: SignNow + categories: + - legal + auth_mode: OAUTH2 + authorization_url: https://app.signnow.com/authorize + token_url: https://api.signnow.com/oauth2/token + disable_pkce: true + token_request_auth_method: basic + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://api.signnow.com + docs: https://docs.nango.dev/integrations/all/signnow + +signnow-sandbox: + display_name: SignNow (sandbox) + categories: + - legal + auth_mode: OAUTH2 + authorization_url: https://app-eval.signnow.com/authorize + token_url: https://api-eval.signnow.com/oauth2/token + disable_pkce: true + token_request_auth_method: basic + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://api-eval.signnow.com + docs: https://docs.nango.dev/integrations/all/signnow + +servicenow: + display_name: ServiceNow + categories: + - productivity + auth_mode: OAUTH2 + authorization_url: https://${connectionConfig.subdomain}.service-now.com/oauth_auth.do + token_url: https://${connectionConfig.subdomain}.service-now.com/oauth_token.do + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://${connectionConfig.subdomain}.service-now.com + docs: https://docs.nango.dev/integrations/all/servicenow + connection_config: + subdomain: + type: string + title: ServiceNow Domain + description: The subdomain of your ServiceNow account + pattern: '^[a-z0-9_-]+$' + example: domain + suffix: .service-now.com + prefix: https:// + +sharepoint-online: + display_name: SharePoint Online + categories: + - storage + - communication + alias: microsoft + docs: https://docs.nango.dev/integrations/all/sharepoint-online + +sharepoint-online-v1: + display_name: SharePoint Online (v1) + categories: + - storage + - communication + auth_mode: TWO_STEP + token_url: https://login.microsoftonline.com/${connectionConfig.tenantId}/oauth2/token + body_format: form + token_params: + client_id: ${credential.clientId} + grant_type: client_credentials + resource: https://${connectionConfig.tenantId}.sharepoint.com + client_assertion_type: urn:ietf:params:oauth:client-assertion-type:jwt-bearer + client_assertion: ${credential.assertion} + token_headers: + content-type: application/x-www-form-urlencoded + proxy: + base_url: https://${connectionConfig.tenantName}.sharepoint.com + headers: + accept: application/json;odata=verbose + token_response: + token: access_token + token_expiration: expires_in + token_expiration_strategy: expireIn + docs: https://docs.nango.dev/integrations/all/sharepoint-online + docs_connect: https://docs.nango.dev/integrations/all/sharepoint-online-v1/connect + connection_config: + tenantId: + type: string + title: Tenant ID + description: The unique identifier for your organization that uses Microsoft services + format: uuid + example: a1b2c3d4-e5f6-47a8-9b0c-d1234567890f + doc_section: '#step-1-finding-your-tenant-id' + order: 1 + tenantName: + type: string + title: Tenant Name + description: The initial domain name for your Microsoft services tenant + example: mycompany + pattern: '^[a-zA-Z0-9]+$' + doc_section: '#step-2-finding-your-tenant-name' + order: 2 + credentials: + clientId: + type: string + title: Client ID + description: Your application Client ID + secret: true + doc_section: '#step-3-finding-your-client-id' + assertion: + type: string + title: Client Assertion + description: Your generated client assertion + secret: true + doc_section: '#step-4-generating-your-client-assertion' + +shipstation: + display_name: Shipstation + categories: + - e-commerce + auth_mode: BASIC + proxy: + base_url: https://ssapi.shipstation.com + retry: + after: 'x-rate-limit-reset' + verification: + method: GET + endpoint: /users + docs: https://docs.nango.dev/integrations/all/shipstation + docs_connect: https://docs.nango.dev/integrations/all/shipstation/connect + credentials: + username: + type: string + title: API Key + description: Your ShipStation API key + doc_section: '#step-1-finding-shipstation-api-key-and-api-secret' + password: + type: string + title: API Secret + description: Your Shipstation API secret + # https://www.shipstation.com/docs/api/requirements/#authentication + # Shipstation is using basic auth with API key and secret + doc_section: '#step-1-finding-shipstation-api-key-and-api-secret' + +shopify: + display_name: Shopify + categories: + - e-commerce + auth_mode: OAUTH2 + authorization_url: https://${connectionConfig.subdomain}.myshopify.com/admin/oauth/authorize + token_url: https://${connectionConfig.subdomain}.myshopify.com/admin/oauth/access_token + proxy: + base_url: https://${connectionConfig.subdomain}.myshopify.com + headers: + x-shopify-access-token: ${accessToken} + docs: https://docs.nango.dev/integrations/all/shopify + docs_connect: https://docs.nango.dev/integrations/all/shopify/connect + connection_config: + subdomain: + type: string + title: Shopify Domain + description: The subdomain of your Shopify account + pattern: '^[a-z0-9_-]+$' + example: domain + suffix: .myshopify.com + prefix: https:// + doc_section: '#step-1-finding-your-shopify-domain' + +shopify-api-key: + display_name: Shopify (api key) + categories: + - e-commerce + auth_mode: API_KEY + proxy: + base_url: https://${connectionConfig.subdomain}.myshopify.com + headers: + x-shopify-access-token: ${apiKey} + content-type: application/json + verification: + method: POST + endpoint: /admin/api/2024-10/graphql.json?query=%7B__schema%7Btypes%7Bname%2Ckind%2Cfields%7Bname%7D%7D%7D%7D + docs: https://docs.nango.dev/integrations/all/shopify + docs_connect: https://docs.nango.dev/integrations/all/shopify-api-key/connect + connection_config: + subdomain: + type: string + title: Shopify Domain + description: The subdomain of your Shopify account + pattern: '^[a-z0-9_-]+$' + example: domain + suffix: .myshopify.com + prefix: https:// + doc_section: '#step-1-finding-your-shopify-domain' + order: 1 + credentials: + apiKey: + type: string + title: API Access Token + description: The API access token generated + example: shpat_***************c03266f + pattern: '^shpat_[a-f0-9]{32}$' + doc_section: '#step-2-generating-your-api-access-token' + +shopify-scim: + display_name: Shopify (SCIM API) + categories: + - e-commerce + auth_mode: API_KEY + proxy: + base_url: https://shopifyscim.com/scim + headers: + authorization: Bearer ${apiKey} + accept: application/json + content-type: application/json + retry: + after: 'retry-after' + docs: https://docs.nango.dev/integrations/all/shopify + docs_connect: https://docs.nango.dev/integrations/all/shopify-scim/connect + credentials: + apiKey: + type: string + title: SCIM API Token + description: The SCIM API token generated from your Shopify organization settings. + doc_section: '#step-1-generating-your-scim-api-token' + +shortcut: + display_name: Shortcut + categories: + - dev-tools + - productivity + auth_mode: API_KEY + proxy: + base_url: https://api.app.shortcut.com + headers: + shortcut-token: ${apiKey} + verification: + method: GET + endpoint: /v3/member + docs: https://docs.nango.dev/integrations/all/shortcut + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Shortcut account + +slack: + display_name: Slack + categories: + - productivity + auth_mode: OAUTH2 + authorization_url: https://slack.com/oauth/v2/authorize + token_url: https://slack.com/api/oauth.v2.access + token_response_metadata: + - incoming_webhook.url + - incoming_webhook.channel + - incoming_webhook.channel_id + - bot_user_id + - team.id + proxy: + base_url: https://slack.com/api + paginate: + type: cursor + cursor_path_in_response: response_metadata.next_cursor + cursor_name_in_request: cursor + limit_name_in_request: limit + webhook_routing_script: slackWebhookRouting + docs: https://docs.nango.dev/integrations/all/slack + +smartrecruiters-api-key: + display_name: Smartrecruiters (api key) + auth_mode: API_KEY + proxy: + base_url: https://api.smartrecruiters.com + headers: + x-smarttoken: ${apiKey} + verification: + method: GET + endpoint: /feed/publications + docs: https://docs.nango.dev/integrations/all/smartrecruiters + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Smartrecruiters account + +smartsheet: + display_name: Smartsheet + auth_mode: OAUTH2 + authorization_url: https://app.smartsheet.com/b/authorize + token_url: https://api.smartsheet.com/2.0/token + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + proxy: + base_url: https://api.smartsheet.com + docs: https://docs.nango.dev/integrations/all/smartsheet + +smugmug: + display_name: Smugmug + auth_mode: OAUTH1 + request_url: https://api.smugmug.com/services/oauth/1.0a/getRequestToken + authorization_url: https://api.smugmug.com/services/oauth/1.0a/authorize + token_url: https://api.smugmug.com/services/oauth/1.0a/getAccessToken + scope_separator: ',' + signature_method: 'PLAINTEXT' + proxy: + base_url: https://www.smugmug.com + docs: https://docs.nango.dev/integrations/all/smugmug + +snowflake: + display_name: Snowflake + categories: + - dev-tools + auth_mode: OAUTH2 + authorization_url: https://${connectionConfig.snowflake_account_url}/oauth/authorize + token_url: https://${connectionConfig.snowflake_account_url}/oauth/token-request + token_request_auth_method: basic + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://${connectionConfig.snowflake_account_url} + docs: https://docs.nango.dev/integrations/all/snowflake + connection_config: + snowflake_account_url: + type: string + title: Domain + description: The domain of your Snowflake account + format: hostname + prefix: https:// + +splitwise: + display_name: Splitwise + categories: + - payment + - social + auth_mode: OAUTH2 + authorization_url: https://secure.splitwise.com/oauth/authorize + token_url: https://secure.splitwise.com/oauth/token + proxy: + base_url: https://secure.splitwise.com + docs: https://docs.nango.dev/integrations/all/splitwise + +spotify: + display_name: Spotify + categories: + - other + auth_mode: OAUTH2 + authorization_url: https://accounts.spotify.com/authorize + token_url: https://accounts.spotify.com/api/token + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://api.spotify.com + docs: https://docs.nango.dev/integrations/all/spotify +spotify-oauth2-cc: + display_name: Spotify (custom) + categories: + - other + auth_mode: OAUTH2_CC + token_url: https://accounts.spotify.com/api/token + token_request_auth_method: basic + scope_separator: ' ' + token_params: + grant_type: client_credentials + proxy: + base_url: https://api.spotify.com + docs: https://docs.nango.dev/integrations/all/spotify + +squarespace: + display_name: Squarespace + categories: + - dev-tools + - design + auth_mode: OAUTH2 + authorization_url: https://login.squarespace.com/api/1/login/oauth/provider/authorize + token_url: https://login.squarespace.com/api/1/login/oauth/provider/tokens + token_request_auth_method: basic + scope_separator: ',' + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://api.squarespace.com + headers: + user-agent: ${connectionConfig.customappDescription} + docs: https://docs.nango.dev/integrations/all/squarespace + connection_config: + customappDescription: + type: string + title: User Agent + description: The user agent of your custom app + +squareup: + display_name: Squareup + categories: + - payment + auth_mode: OAUTH2 + authorization_url: https://connect.squareup.com/oauth2/authorize + token_url: https://connect.squareup.com/oauth2/token + disable_pkce: true + decode_url: true + authorization_params: + response_type: code + session: false + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://connect.squareup.com + docs: https://docs.nango.dev/integrations/all/squareup + +squareup-sandbox: + display_name: Squareup (sandbox) + auth_mode: OAUTH2 + authorization_url: https://connect.squareupsandbox.com/oauth2/authorize + token_url: https://connect.squareupsandbox.com/oauth2/token + disable_pkce: true + authorization_params: + response_type: code + session: false + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://connect.squareupsandbox.com + docs: https://docs.nango.dev/integrations/all/squareup + +stackexchange: + display_name: Stack Exchange + categories: + - knowledge-base + - support + auth_mode: OAUTH2 + authorization_url: https://stackoverflow.com/oauth + token_url: https://stackoverflow.com/oauth/access_token/json + default_scopes: + - no_expiry + proxy: + base_url: https://api.stackexchange.com + docs: https://docs.nango.dev/integrations/all/stackexchange + +strava: + display_name: Strava (mobile) + categories: + - social + - sports + auth_mode: OAUTH2 + authorization_url: https://www.strava.com/oauth/mobile/authorize + token_url: https://www.strava.com/api/v3/oauth/token + scope_separator: ',' + authorization_params: + response_type: code + approval_prompt: auto + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://www.strava.com + docs: https://docs.nango.dev/integrations/all/strava + +strava-web: + display_name: Strava (web) + categories: + - social + - sports + auth_mode: OAUTH2 + authorization_url: https://www.strava.com/oauth/authorize + token_url: https://www.strava.com/api/v3/oauth/token + scope_separator: ',' + authorization_params: + response_type: code + approval_prompt: force + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://www.strava.com + docs: https://docs.nango.dev/integrations/all/strava + +stripe: + display_name: Stripe + categories: + - payment + auth_mode: OAUTH2 + authorization_url: https://connect.stripe.com/oauth/authorize + token_url: https://connect.stripe.com/oauth/token + proxy: + base_url: https://api.stripe.com + docs: https://docs.nango.dev/integrations/all/stripe + +stripe-express: + display_name: Stripe Express + categories: + - payment + auth_mode: OAUTH2 + authorization_url: https://connect.stripe.com/express/oauth/authorize + token_url: https://connect.stripe.com/oauth/token + token_response_metadata: + - stripe_user_id + proxy: + base_url: https://api.stripe.com + docs: https://docs.nango.dev/integrations/all/stripe-express + +stripe-app: + display_name: Stripe App + categories: + - payment + auth_mode: OAUTH2 + authorization_url: https://marketplace.stripe.com/oauth/v2/authorize + token_url: https://api.stripe.com/v1/oauth/token + disable_pkce: true + proxy: + base_url: https://api.stripe.com + refresh_params: + grant_type: refresh_token + docs: https://docs.nango.dev/integrations/all/stripe-app + +stripe-app-sandbox: + display_name: Stripe App (sandbox) + auth_mode: OAUTH2 + authorization_url: https://marketplace.stripe.com/oauth/v2/${connectionConfig.appDomain}/authorize + token_url: https://api.stripe.com/v1/oauth/token + disable_pkce: true + proxy: + base_url: https://api.stripe.com + refresh_params: + grant_type: refresh_token + docs: https://docs.nango.dev/integrations/all/stripe-app + connection_config: + appDomain: + type: string + title: App Domain + description: The domain of your Stripe app + +survey-monkey: + display_name: SurveyMonkey + categories: + - surveys + auth_mode: OAUTH2 + authorization_url: https://api.surveymonkey.com/oauth/authorize + token_url: https://api.surveymonkey.com/oauth/token + disable_pkce: true + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + proxy: + base_url: https://api.surveymonkey.com + docs: https://docs.nango.dev/integrations/all/survey-monkey + +tapclicks: + display_name: TapClicks + auth_mode: OAUTH2_CC + categories: + - marketing + - analytics + token_url: https://api.tapclicks.com/oauth/accesstoken + token_params: + grant_type: client_credentials + proxy: + base_url: https://api.tapclicks.com/v2 + docs: https://docs.nango.dev/integrations/all/tapclicks + docs_connect: https://docs.nango.dev/integrations/all/tapclicks/connect + +tableau: + display_name: Tableau + categories: + - analytics + auth_mode: TABLEAU + token_url: https://${connectionConfig.myServer}/api/${connectionConfig.version}/auth/signin + proxy: + headers: + accept: application/json + content-type: application/json + base_url: https://${connectionConfig.myServer}/api/${connectionConfig.version} + docs: https://docs.nango.dev/integrations/all/tableau + connection_config: + myServer: + type: string + title: Domain + description: The domain of your Tableau instance + format: hostname + prefix: https:// + version: + type: string + title: API Version + description: The version of the Tableau API to use + +teamtailor: + display_name: Teamtailor + categories: + - ats + auth_mode: API_KEY + proxy: + base_url: https://${connectionConfig.extension}.teamtailor.com + retry: + after: 'x-rate-limit-reset' + headers: + authorization: Token token=${apiKey} + x-api-version: '20210218' + verification: + method: GET + endpoint: /v1/users + docs: https://docs.nango.dev/integrations/all/teamtailor + connection_config: + extension: + type: string + title: Teamtailor Domain + description: The subdomain of your Teamtailor instance + pattern: '^[a-z0-9_-]+$' + example: domain + suffix: .teamtailor.com + prefix: https:// + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Teamtailor account + +teamwork: + display_name: Teamwork + categories: + - productivity + - ticketing + auth_mode: OAUTH2 + authorization_url: https://www.teamwork.com/launchpad/login + token_url: https://www.teamwork.com/launchpad/v1/token.json + token_response_metadata: + - installation.apiEndPoint + proxy: + base_url: ${connectionConfig.installation.apiEndPoint} + docs: https://docs.nango.dev/integrations/all/teamwork + +ticktick: + display_name: TickTick + categories: + - productivity + - ticketing + auth_mode: OAUTH2 + authorization_url: https://ticktick.com/oauth/authorize + token_url: https://ticktick.com/oauth/token + scope_separator: ' ' + proxy: + base_url: https://api.ticktick.com + docs: https://docs.nango.dev/integrations/all/ticktick + +tiktok-accounts: + display_name: TikTok Accounts + categories: + - social + auth_mode: OAUTH2 + authorization_url: https://www.tiktok.com/v2/auth/authorize/ + token_url: https://business-api.tiktok.com/open_api/v1.3/tt_user/oauth2/token/ + refresh_url: https://business-api.tiktok.com/open_api/v1.3/tt_user/oauth2/refresh_token/ + proxy: + base_url: https://business-api.tiktok.com/open_api/v1.3/ + authorization_params: + response_type: code + authorization_url_replacements: + client_id: client_key + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + scope_separator: ',' + docs: https://docs.nango.dev/integrations/all/tiktok-accounts + +tiktok-ads: + display_name: TikTok Ads + categories: + - social + auth_mode: OAUTH2 + authorization_url: https://business-api.tiktok.com/portal/auth + token_url: https://business-api.tiktok.com/open_api/v1.3/oauth2/access_token/ + proxy: + base_url: https://business-api.tiktok.com/open_api/v1.3/ + headers: + access-token: ${accessToken} + token_params: + grant_type: authorization_code + authorization_url_replacements: + client_id: app_id + docs: https://docs.nango.dev/integrations/all/tiktok-ads + +timely: + display_name: Timely + categories: + - productivity + auth_mode: OAUTH2 + authorization_url: https://api.timelyapp.com/1.1/oauth/authorize + token_url: https://api.timelyapp.com/1.1/oauth/token + disable_pkce: true + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + proxy: + base_url: https://api.timelyapp.com + docs: https://docs.nango.dev/integrations/all/timely + +thrivecart-oauth: + display_name: ThriveCart (OAuth) + categories: + - e-commerce + - payment + auth_mode: OAUTH2 + authorization_url: https://thrivecart.com/authorization/new + token_url: https://thrivecart.com/authorization/token + scope_separator: ' ' + proxy: + base_url: https://thrivecart.com/api/external + docs: https://docs.nango.dev/integrations/all/thrivecart + +thrivecart-api-key: + display_name: ThriveCart (api key) + categories: + - e-commerce + - payment + auth_mode: API_KEY + proxy: + base_url: https://thrivecart.com/api/external + headers: + authorization: Bearer ${apiKey} + verification: + method: GET + endpoint: /ping + docs: https://docs.nango.dev/integrations/all/thrivecart + credentials: + apiKey: + type: string + title: API Key + description: The API key for your ThriveCart account + example: 'ASYDV5S8-0BSO1SH2-4BH5PO7U-YF8SV3CZ' + pattern: '^[A-Z0-9]{8}-[A-Z0-9]{10}-[A-Z0-9]{8}-[A-Z0-9]{8}$' + +tremendous: + display_name: Tremendous + categories: + - payment + auth_mode: OAUTH2 + authorization_url: https://api.tremendous.com/oauth/authorize + token_url: https://api.tremendous.com/oauth/token + scope_separator: ' ' + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://api.tremendous.com/api/v2 + docs: https://docs.nango.dev/integrations/all/tremendous + +tremendous-sandbox: + display_name: Tremendous (sandbox) + categories: + - payment + auth_mode: OAUTH2 + authorization_url: https://testflight.tremendous.com/oauth/authorize + token_url: https://testflight.tremendous.com/oauth/token + scope_separator: ' ' + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://testflight.tremendous.com/api/v2 + docs: https://docs.nango.dev/integrations/all/tremendous + +trello: + display_name: Trello + categories: + - productivity + - ticketing + auth_mode: OAUTH1 + request_url: https://trello.com/1/OAuthGetRequestToken + authorization_url: https://trello.com/1/OAuthAuthorizeToken + token_url: https://trello.com/1/OAuthGetAccessToken + signature_method: 'HMAC-SHA1' + scope_separator: ',' + authorization_params: + expiration: never + proxy: + base_url: https://api.trello.com + docs: https://docs.nango.dev/integrations/all/trello + +trello-scim: + display_name: Trello (SCIM API) + categories: + - productivity + - ticketing + auth_mode: API_KEY + proxy: + base_url: https://trello.com/scim + headers: + authorization: Bearer ${apiKey} + verification: + method: GET + endpoint: /v2/users?sortBy=displayName&count=10 + docs: https://docs.nango.dev/integrations/all/trello + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Trello scim account + doc_section: '#step-1-finding-your-trello-api-key' + +tsheetsteam: + display_name: TSheets + categories: + - hr + - productivity + auth_mode: OAUTH2 + authorization_url: https://rest.tsheets.com/api/v1/authorize + token_url: https://rest.tsheets.com/api/v1/grant + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://rest.tsheets.com/api/v1 + docs: https://docs.nango.dev/integrations/all/tsheetsteam + +todoist: + display_name: Todoist + categories: + - productivity + - ticketing + auth_mode: OAUTH2 + authorization_url: https://todoist.com/oauth/authorize + token_url: https://todoist.com/oauth/access_token + scope_separator: ',' + proxy: + base_url: https://api.todoist.com + docs: https://docs.nango.dev/integrations/all/todoist + +tumblr: + display_name: Tumblr + categories: + - social + - communication + auth_mode: OAUTH2 + authorization_url: https://www.tumblr.com/oauth2/authorize + token_url: https://api.tumblr.com/v2/oauth2/token + scope_separator: ' ' + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://api.tumblr.com/v2 + docs: https://docs.nango.dev/integrations/all/tumblr + +twitch: + display_name: Twitch + categories: + - gaming + - social + - sports + - video + auth_mode: OAUTH2 + authorization_url: https://id.twitch.tv/oauth2/authorize + token_url: https://id.twitch.tv/oauth2/token + authorization_params: + force_verify: false + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://api.twitch.tv + docs: https://docs.nango.dev/integrations/all/twitch + +twitter: + display_name: Twitter (v1) + categories: + - marketing + - social + auth_mode: OAUTH1 + request_url: https://api.twitter.com/oauth/request_token + authorization_url: https://api.twitter.com/oauth/authorize + token_url: https://api.twitter.com/oauth/access_token + signature_method: 'HMAC-SHA1' + request_params: + x_auth_access_type: write + proxy: + base_url: https://api.twitter.com + docs: https://docs.nango.dev/integrations/all/twitter +twitter-v2: + display_name: Twitter (v2) + categories: + - marketing + - social + auth_mode: OAUTH2 + authorization_url: https://twitter.com/i/oauth2/authorize + token_url: https://api.twitter.com/2/oauth2/token + token_request_auth_method: basic + authorization_params: + response_type: code + response_mode: query + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + default_scopes: + - offline.access + proxy: + base_url: https://api.twitter.com + docs: https://docs.nango.dev/integrations/all/twitter +twitter-oauth2-cc: + display_name: Twitter (custom) + categories: + - marketing + - social + auth_mode: OAUTH2_CC + token_url: https://api.twitter.com/oauth2/token + token_request_auth_method: basic + scope_separator: ' ' + token_params: + grant_type: client_credentials + proxy: + base_url: https://api.twitter.com + docs: https://docs.nango.dev/integrations/all/twitter + +twinfield: + display_name: Twinfield + auth_mode: OAUTH2 + authorization_url: https://login.twinfield.com/auth/authentication/connect/authorize + token_url: https://login.twinfield.com/auth/authentication/connect/token + authorization_params: + response_type: code + nonce: AnotherRandomStringTwinfield + refresh_params: + grant_type: refresh_token + scope_separator: ' ' + default_scopes: + - openid + - twf.user + - twf.organisation + - twf.organisationUser + - offline_access + disable_pkce: true + proxy: + base_url: https://${connectionConfig.cluster}.twinfield.com + docs: https://docs.nango.dev/integrations/all/twinfield + connection_config: + cluster: + type: string + title: Twinfield Cluster + description: The cluster to your Twinfield instance + pattern: '^[a-z0-9_-]+$' + example: accounting + suffix: .twinfield.com + prefix: https:// + +twenty-crm: + display_name: Twenty CRM + categories: + - crm + auth_mode: API_KEY + proxy: + base_url: https://api.twenty.com/rest + headers: + authorization: Bearer ${apiKey} + retry: + after: 'retry-after' + verification: + method: GET + endpoint: /companies + docs: https://docs.nango.dev/integrations/all/twenty-crm + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Twenty CRM account + example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIyMTIxMjEyMS0yNmExLTRkODktYjQ2YS0wNDI0NTViODM3N2YiLCJ0eXBlIjoiQVBJX0tFWSIsIndvcmtzcGFjZUlkIjoiMjEyMTIxMjEtMjZhMS00ZDg5LWI0NmEtMDQyNDU1YjgzNzdmIiwiaWF0IjoxNzMxMzA5MzQwLCJleHAiOjQ4ODQ5MDU3MzksImp0aSI6ImVmZTg4MjcxLTM4OWItNDk5Mi04MjYwLWZjNGIxZmYxYjRiMSJ9.n3tohFIEBBRMsyas_agbh3-KvKXYUnjyhrYzTHYC3vc' + pattern: '^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$' + +twenty-crm-self-hosted: + display_name: Twenty CRM (Self Hosted) + categories: + - crm + auth_mode: API_KEY + proxy: + base_url: https://${connectionConfig.domain}/rest + headers: + authorization: Bearer ${apiKey} + retry: + after: 'retry-after' + verification: + method: GET + endpoint: /companies + docs: https://docs.nango.dev/integrations/all/twenty-crm + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Twenty CRM account + example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIyMTIxMjEyMS0yNmExLTRkODktYjQ2YS0wNDI0NTViODM3N2YiLCJ0eXBlIjoiQVBJX0tFWSIsIndvcmtzcGFjZUlkIjoiMjEyMTIxMjEtMjZhMS00ZDg5LWI0NmEtMDQyNDU1YjgzNzdmIiwiaWF0IjoxNzMxMzA5MzQwLCJleHAiOjQ4ODQ5MDU3MzksImp0aSI6ImVmZTg4MjcxLTM4OWItNDk5Mi04MjYwLWZjNGIxZmYxYjRiMSJ9.n3tohFIEBBRMsyas_agbh3-KvKXYUnjyhrYzTHYC3vc' + pattern: '^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$' + connection_config: + domain: + type: string + title: Twenty CRM domain + description: The domain of your Twnety CRM instance + pattern: '^[A-Za-z0-9.-]+\.[A-Za-z]{2,}$' + example: domain + +typeform: + display_name: Typeform + categories: + - surveys + auth_mode: OAUTH2 + authorization_url: https://api.typeform.com/oauth/authorize + token_url: https://api.typeform.com/oauth/token + disable_pkce: true + default_scopes: + - offline + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://api.typeform.com + docs: https://docs.nango.dev/integrations/all/typeform + +typefully: + display_name: Typefully + categories: + - analytics + - communication + - social + auth_mode: API_KEY + proxy: + base_url: https://api.typefully.com + headers: + x-api-key: Bearer ${apiKey} + verification: + method: GET + endpoint: /v1/notifications/ + docs: https://docs.nango.dev/integrations/all/typefully + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Typefully account + +uber: + display_name: Uber + auth_mode: OAUTH2 + authorization_url: https://login.uber.com/oauth/v2/authorize + token_url: https://login.uber.com/oauth/v2/token + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://api.uber.com + docs: https://docs.nango.dev/integrations/all/uber + +unanet: + display_name: Unanet + categories: + - crm + - erp + - accounting + auth_mode: BASIC + proxy: + headers: + x-compass-firm-id: ${connectionConfig.firmId} + x-compass-api-key: ${connectionConfig.apiKey} + base_url: https://compass.cosential.com + verification: + method: GET + endpoint: /api/projects + docs: https://docs.nango.dev/integrations/all/unanet + docs_connect: https://docs.nango.dev/integrations/all/unanet/connect + connection_config: + firmId: + type: string + title: Firm ID + description: The firm ID of your Unanet instance + doc_section: '#step-2-finding-the-firm-id' + apiKey: + type: string + title: API Key + description: The API key of your Unanet instance + secret: true + doc_section: '#step-3-finding-the-api-key' + credentials: + username: + type: string + title: User name + description: Your Unanet username + doc_section: '#step-1-finding-username-and-password' + password: + type: string + title: Password + description: Your Unanet password + default_value: '' + doc_section: '#step-1-finding-username-and-password' + +unauthenticated: + display_name: Unauthenticated + auth_mode: NONE + webhook_routing_script: unauthenticatedWebhookRouting + docs: https://docs.nango.dev/integrations/all/unauthenticated + +unipile: + display_name: Unipile + categories: + - crm + - marketing + auth_mode: API_KEY + proxy: + base_url: https://${connectionConfig.subdomain}.unipile.com:${connectionConfig.port} + headers: + x-api-key: ${apiKey} + verification: + method: GET + endpoint: /api/v1/contacts + docs: https://docs.nango.dev/integrations/all/unipile + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Unipile instance + connection_config: + subdomain: + type: string + title: Subdomain + description: The subdomain of your Unipile instance + pattern: '^[a-z0-9_-]+$' + example: api1 + suffix: .unipile.com + prefix: https:// + port: + type: string + title: Port + description: The port of your Unipile instance + pattern: '^[0-9]+$' + example: '13113' + +vimeo: + display_name: Vimeo + categories: + - video + auth_mode: OAUTH2 + authorization_url: https://api.vimeo.com/oauth/authorize + token_url: https://api.vimeo.com/oauth/access_token + token_request_auth_method: basic + scope_separator: ' ' + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + proxy: + base_url: https://api.vimeo.com + docs: https://docs.nango.dev/integrations/all/vimeo + +vimeo-basic: + display_name: Vimeo (basic auth) + categories: + - video + auth_mode: BASIC + proxy: + base_url: https://api.vimeo.com + verification: + method: GET + endpoint: / + docs: https://docs.nango.dev/integrations/all/vimeo + +wakatime: + display_name: Wakatime + categories: + - analytics + - dev-tools + auth_mode: OAUTH2 + authorization_url: https://wakatime.com/oauth/authorize + token_url: https://wakatime.com/oauth/token + proxy: + base_url: https://wakatime.com + docs: https://docs.nango.dev/integrations/all/wakatime + +wave-accounting: + display_name: Wave Accounting + categories: + - accounting + auth_mode: OAUTH2 + authorization_url: https://api.waveapps.com/oauth2/authorize + token_url: https://api.waveapps.com/oauth2/token/ + proxy: + base_url: https://gql.waveapps.com + docs: https://docs.nango.dev/integrations/all/wave-accounting + +wealthbox: + display_name: Wealthbox + categories: + - crm + auth_mode: OAUTH2 + authorization_url: https://app.crmworkspace.com/oauth/authorize + token_url: https://app.crmworkspace.com/oauth/token + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://api.crmworkspace.com + docs: https://docs.nango.dev/integrations/all/wealthbox + +webflow: + display_name: Webflow + categories: + - dev-tools + - design + - cms + auth_mode: OAUTH2 + authorization_url: https://webflow.com/oauth/authorize + token_url: https://api.webflow.com/oauth/access_token + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + proxy: + base_url: https://api.webflow.com + docs: https://docs.nango.dev/integrations/all/webflow + +whatsapp-business: + display_name: WhatsApp Business + categories: + - communication + - marketing + auth_mode: API_KEY + proxy: + headers: + authorization: Bearer ${apiKey} + content-type: application/json + base_url: https://graph.facebook.com + verification: + endpoint: /v21.0/me + method: GET + docs: https://docs.nango.dev/integrations/all/whatsapp-business + credentials: + apiKey: + type: string + title: API Key + description: The access token to your whatsapp account + pattern: '^[a-zA-Z0-9]+$' + +whoop: + display_name: Whoop + categories: + - sports + auth_mode: OAUTH2 + authorization_url: https://api.prod.whoop.com/oauth/oauth2/auth + token_url: https://api.prod.whoop.com/oauth/oauth2/token + authorization_params: + response_type: code + proxy: + base_url: https://api.prod.whoop.com/ + retry: + after: 'x-ratelimit-reset' + paginate: + type: cursor + offset_name_in_request: nextToken + limit_name_in_request: limit + docs: https://docs.nango.dev/integrations/all/whoop + +wildix-pbx: + display_name: Wildix PBX + auth_mode: OAUTH2 + authorization_url: https://${connectionConfig.subdomain}.wildixin.com/authorization/oauth2 + token_url: https://${connectionConfig.subdomain}.wildixin.com/authorization/oauth2Token + authorization_params: + response_type: code + redirect_uri_metadata: + - subdomain + docs: https://docs.nango.dev/integrations/all/wildix-pbx + proxy: + base_url: https://${connectionConfig.subdomain}.wildixin.com + connection_config: + subdomain: + type: string + title: Wildix Domain + description: The subdomain of your Wildix instance + pattern: '^[a-z0-9_-]+$' + example: domain + suffix: .wildixin.com + prefix: https:// + +wordpress: + display_name: WordPress + categories: + - dev-tools + - design + - cms + auth_mode: OAUTH2 + authorization_url: https://public-api.wordpress.com/oauth2/authorize + token_url: https://public-api.wordpress.com/oauth2/token + scope_separator: ' ' + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + proxy: + base_url: https://public-api.wordpress.com/rest/v1 + docs: https://docs.nango.dev/integrations/all/wordpress + +woocommerce: + display_name: WooCommerce + categories: + - e-commerce + - dev-tools + - design + auth_mode: BASIC + proxy: + base_url: https://${connectionConfig.storeURL} + verification: + method: GET + endpoint: /wp-json/wc/v3/customers + docs: https://docs.nango.dev/integrations/all/woocommerce + docs_connect: https://docs.nango.dev/integrations/all/woocommerce/connect + connection_config: + storeURL: + type: string + title: Domain + description: The domain of your WooCommerce store + credentials: + username: + type: string + title: User name + description: Your woocommerce Consumer Key + doc_section: '#step-1-finding-your-woocommerce-consumer-key' + password: + type: string + title: Password + description: Your woocommerce Consumer Secret + default_value: '' + doc_section: '#step-2-finding-your-woocommerce-consumer-secret' + +workable: + display_name: Workable + categories: + - ats + auth_mode: API_KEY + proxy: + headers: + authorization: Bearer ${apiKey} + base_url: https://${connectionConfig.subdomain}.workable.com + retry: + at: 'x-rate-limit-reset' + post_connection_script: workablePostConnection + docs: https://docs.nango.dev/integrations/all/workable + docs_connect: https://docs.nango.dev/integrations/all/workable/connect + connection_config: + subdomain: + type: string + title: Workable Domain + description: The subdomain of your Workable account + pattern: '^[a-z0-9_-]+$' + example: domain + suffix: .workable.com + prefix: https:// + optional: true + credentials: + apiKey: + type: string + title: API Key + description: The API key for your Workable account + doc_section: '#step-1-finding-workable-api-key' + +workable-oauth: + display_name: Workable (OAuth) + categories: + - ats + auth_mode: OAUTH2 + authorization_url: https://www.workable.com/oauth/authorize + token_url: https://www.workable.com/oauth/token + scope_separator: '+' + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://${connectionConfig.subdomain}.workable.com + retry: + at: 'x-rate-limit-reset' + docs: https://docs.nango.dev/integrations/all/workable + connection_config: + subdomain: + type: string + title: Workable Domain + description: The subdomain of your Workable account + pattern: '^[a-z0-9_-]+$' + example: domain + suffix: .workable.com + prefix: https:// + +workday: + display_name: Workday + categories: + - hr + auth_mode: BASIC + proxy: + base_url: https://${connectionConfig.subdomain}.workday.com + docs: https://docs.nango.dev/integrations/all/workday + docs_connect: https://docs.nango.dev/integrations/all/workday/connect + connection_config: + subdomain: + type: string + title: Workday Domain + description: The subdomain of your Workday account + pattern: '^[a-z0-9_-]+$' + example: domain + suffix: .workday.com + prefix: https:// + credentials: + username: + type: string + title: Client ID + description: Workday Client ID + doc_section: '#step-2-find-your-workday-client-id-and-client-secret' + password: + type: string + title: Client Secret + description: Workday Client Secret + doc_section: '#step-2-find-your-workday-client-id-and-client-secret' + # https://community.workday.com/sites/default/files/file-hosting/productionapi/index.html + # Workday is using basic auth with client ID and client secret as username and password + +wrike: + display_name: Wrike + categories: + - productivity + auth_mode: OAUTH2 + authorization_url: https://login.wrike.com/oauth2/authorize/v4 + token_url: https://login.wrike.com/oauth2/token + scope_separator: ',' + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + token_response_metadata: + - host + proxy: + base_url: https://${connectionConfig.host}/api/v4 + docs: https://docs.nango.dev/integrations/all/wrike + connection_config: + host: + type: string + title: Domain + description: The domain of your Wrike account + format: hostname + prefix: https:// + +xero: + display_name: Xero + categories: + - accounting + auth_mode: OAUTH2 + authorization_url: https://login.xero.com/identity/connect/authorize + token_url: https://identity.xero.com/connect/token + authorization_params: + response_type: code + default_scopes: + - offline_access + - openid + proxy: + base_url: https://api.xero.com + retry: + after: 'retry-after' + post_connection_script: xeroPostConnection + docs: https://docs.nango.dev/integrations/all/xero + +yahoo: + display_name: Yahoo + categories: + - social + auth_mode: OAUTH2 + authorization_url: https://api.login.yahoo.com/oauth2/request_auth + token_url: https://api.login.yahoo.com/oauth2/get_token + proxy: + base_url: https://${connectionConfig.apiDomain} + docs: https://docs.nango.dev/integrations/all/yahoo + connection_config: + apiDomain: + type: string + title: API Domain + description: The domain to the API you want to connect to + format: hostname + example: fantasysports.yahooapis.com + prefix: https:// + +yandex: + display_name: Yandex + categories: + - social + auth_mode: OAUTH2 + authorization_url: https://oauth.yandex.com/authorize + token_url: https://oauth.yandex.com/token + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://translate.yandex.net + docs: https://docs.nango.dev/integrations/all/yandex + +youtube: + display_name: YouTube + alias: google + categories: + - video + docs: https://docs.nango.dev/integrations/all/youtube + +zapier: + display_name: Zapier + categories: + - dev-tools + auth_mode: OAUTH2 + authorization_url: https://api.zapier.com/v2/authorize + token_url: https://zapier.com/oauth/token + scope_separator: ' ' + default_scopes: + - authentication + - authentication:write + - profile + - zap + - zap:write + proxy: + base_url: https://api.zapier.com + authorization_params: + response_type: code + response_mode: query + state: N@nG0s%rinG + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + docs: https://docs.nango.dev/integrations/all/zapier + +zapier-nla: + display_name: Zapier NLA + auth_mode: OAUTH2 + authorization_url: https://nla.zapier.com/oauth/authorize/ + token_url: https://nla.zapier.com/oauth/token/ + proxy: + base_url: https://nla.zapier.com + docs: https://docs.nango.dev/integrations/all/zapier-nla + +zendesk: + display_name: Zendesk + categories: + - support + - ticketing + auth_mode: OAUTH2 + authorization_url: https://${connectionConfig.subdomain}.zendesk.com/oauth/authorizations/new + token_url: https://${connectionConfig.subdomain}.zendesk.com/oauth/tokens + proxy: + base_url: https://${connectionConfig.subdomain}.zendesk.com + retry: + after: 'retry-after' + paginate: + type: link + limit_name_in_request: per_page + link_path_in_response_body: next_page + docs: https://docs.nango.dev/integrations/all/zendesk + docs_connect: https://docs.nango.dev/integrations/all/zendesk/connect + connection_config: + subdomain: + type: string + title: Zendesk Domain + description: The subdomain of your Zendesk account + pattern: '^[a-z0-9_-]+$' + example: domain + suffix: .zendesk.com + prefix: https:// + doc_section: '#step-1-finding-your-subdomain' + +zenefits: + display_name: Zenefits + categories: + - hr + auth_mode: OAUTH2 + authorization_url: https://secure.zenefits.com/oauth2/platform-authorize + token_url: https://secure.zenefits.com/oauth2/token + authorization_params: + response_type: code + token_params: + grant_type: authorization_code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://api.zenefits.com + docs: https://docs.nango.dev/integrations/all/zenefits + +zoho: + display_name: Zoho + categories: + - accounting + auth_mode: OAUTH2 + authorization_url: https://accounts.zoho.${connectionConfig.extension}/oauth/v2/auth + token_url: https://accounts.zoho.${connectionConfig.extension}/oauth/v2/token + authorization_params: + prompt: consent + access_type: offline + proxy: + base_url: https://www.zohoapis.${connectionConfig.extension} + paginate: + type: offset + response_path: data + offset_name_in_request: page + limit_name_in_request: per_page + docs: https://docs.nango.dev/integrations/all/zoho + connection_config: + extension: + type: string + title: Domain Extension + description: The domain extension of your Zoho account + pattern: '^[a-z.]+$' + prefix: https://accounts.zoho. + example: com + suffix: / + +zoho-books: + display_name: Zoho Books + alias: zoho + docs: https://docs.nango.dev/integrations/all/zoho-books + +zoho-crm: + display_name: Zoho CRM + alias: zoho + docs: https://docs.nango.dev/integrations/all/zoho-crm + +zoho-desk: + display_name: Zoho Desk + categories: + - support + - ticketing + alias: zoho + docs: https://docs.nango.dev/integrations/all/zoho-desk + +zoho-inventory: + display_name: Zoho Inventory + categories: + - e-commerce + alias: zoho + docs: https://docs.nango.dev/integrations/all/zoho-inventory + +zoho-invoice: + display_name: Zoho Invoice + categories: + - invoicing + alias: zoho + docs: https://docs.nango.dev/integrations/all/zoho-invoice + +zoho-mail: + display_name: Zoho Mail + categories: + - productivity + - communication + alias: zoho + proxy: + base_url: https://mail.zoho.${connectionConfig.extension} + docs: https://docs.nango.dev/integrations/all/zoho-mail + connection_config: + extension: + type: string + title: Domain Extension + description: The domain extension of your Zoho account + pattern: '^[a-z.]+$' + +zoho-bigin: + display_name: Zoho Bigin + alias: zoho + docs: https://docs.nango.dev/integrations/all/zoho-bigin + +zoho-people: + display_name: Zoho People + categories: + - hr + alias: zoho + proxy: + base_url: https://people.zoho.com + docs: https://docs.nango.dev/integrations/all/zoho-people + +zoom: + display_name: Zoom + categories: + - video + auth_mode: OAUTH2 + authorization_url: https://zoom.us/oauth/authorize + token_url: https://zoom.us/oauth/token + scope_separator: ',' + authorization_params: + response_type: code + refresh_params: + grant_type: refresh_token + proxy: + base_url: https://api.zoom.us/v2 + paginate: + type: cursor + cursor_path_in_response: next_page_token + cursor_name_in_request: next_page_token + limit_name_in_request: page_size + docs: https://docs.nango.dev/integrations/all/zoom + +zoominfo: + display_name: ZoomInfo + categories: + - crm + - marketing + auth_mode: OAUTH2_CC + proxy: + retry: + after: 'x-ratelimit-reset' + base_url: https://api.zoominfo.com + token_url: https://api.zoominfo.com/authenticate + token_request_auth_method: custom + body_format: json + docs: https://docs.nango.dev/integrations/all/zoominfo + docs_connect: https://docs.nango.dev/integrations/all/zoominfo/connect diff --git a/packages/runner/lib/client.unit.test.ts b/packages/runner/lib/client.unit.test.ts index 85c705dcf19..5733a161bcf 100644 --- a/packages/runner/lib/client.unit.test.ts +++ b/packages/runner/lib/client.unit.test.ts @@ -1,8 +1,7 @@ import { expect, describe, it, beforeAll } from 'vitest'; import { getRunnerClient } from './client.js'; import { server } from './server.js'; -import type { NangoProps } from '@nangohq/shared'; -import type { DBSyncConfig } from '@nangohq/types'; +import type { DBSyncConfig, NangoProps } from '@nangohq/types'; describe('Runner client', () => { const port = 3095; @@ -21,18 +20,12 @@ describe('Runner client', () => { syncId: 'sync-id', syncJobId: 1, lastSyncDate: new Date(), - dryRun: true, attributes: {}, track_deletes: false, - logMessages: { - counts: { updated: 0, added: 0, deleted: 0 }, - messages: [] - }, syncConfig: {} as DBSyncConfig, debug: false, startedAt: new Date(), runnerFlags: {} as any, - stubbedMetadata: {}, endUser: null }; diff --git a/packages/runner/lib/exec.ts b/packages/runner/lib/exec.ts index b01bda945e0..cc55182ba9b 100644 --- a/packages/runner/lib/exec.ts +++ b/packages/runner/lib/exec.ts @@ -1,6 +1,5 @@ -import type { NangoProps } from '@nangohq/shared'; import { AxiosError } from 'axios'; -import { ActionError, NangoSync, NangoAction, instrumentSDK, SpanTypes, validateData, NangoError } from '@nangohq/shared'; +import { SpanTypes } from '@nangohq/shared'; import { Buffer } from 'buffer'; import * as vm from 'node:vm'; import * as url from 'url'; @@ -11,7 +10,9 @@ import * as botbuilder from 'botbuilder'; import tracer from 'dd-trace'; import { errorToObject, metrics, truncateJson } from '@nangohq/utils'; import { logger } from './utils.js'; -import type { RunnerOutput } from '@nangohq/types'; +import type { NangoProps, RunnerOutput } from '@nangohq/types'; +import { instrumentSDK, NangoActionRunner, NangoSyncRunner } from './sdk/sdk.js'; +import { ActionError, SDKError, validateData } from '@nangohq/runner-sdk'; export async function exec( nangoProps: NangoProps, @@ -23,10 +24,10 @@ export async function exec( switch (nangoProps.scriptType) { case 'sync': case 'webhook': - return new NangoSync(nangoProps); + return new NangoSyncRunner(nangoProps); case 'action': case 'on-event': - return new NangoAction(nangoProps); + return new NangoActionRunner(nangoProps); } })(); const nango = process.env['NANGO_TELEMETRY_SDK'] ? instrumentSDK(rawNango) : rawNango; @@ -163,14 +164,14 @@ export async function exec( }; } - if (err instanceof NangoError) { + if (err instanceof SDKError) { span.setTag('error', err); return { success: false, error: { - type: err.type, + type: err.code, payload: truncateJson(err.payload), - status: err.status + status: 500 }, response: null }; diff --git a/packages/runner/lib/exec.unit.test.ts b/packages/runner/lib/exec.unit.test.ts index b6736ff5ffc..ca69b0e083d 100644 --- a/packages/runner/lib/exec.unit.test.ts +++ b/packages/runner/lib/exec.unit.test.ts @@ -1,7 +1,6 @@ import { expect, describe, it } from 'vitest'; import { exec } from './exec.js'; -import type { NangoProps } from '@nangohq/shared'; -import type { DBSyncConfig } from '@nangohq/types'; +import type { DBSyncConfig, NangoProps } from '@nangohq/types'; function getNangoProps(): NangoProps { return { @@ -17,18 +16,12 @@ function getNangoProps(): NangoProps { syncId: 'sync-id', syncJobId: 1, lastSyncDate: new Date(), - dryRun: true, attributes: {}, track_deletes: false, - logMessages: { - counts: { updated: 0, added: 0, deleted: 0 }, - messages: [] - }, syncConfig: {} as DBSyncConfig, debug: false, startedAt: new Date(), runnerFlags: {} as any, - stubbedMetadata: {}, endUser: null }; } diff --git a/packages/runner/lib/monitor.ts b/packages/runner/lib/monitor.ts index 7d0740e2dbb..a81435d1f6f 100644 --- a/packages/runner/lib/monitor.ts +++ b/packages/runner/lib/monitor.ts @@ -1,9 +1,9 @@ import os from 'os'; import fs from 'fs'; -import type { NangoProps } from '@nangohq/shared'; import { httpFetch, logger } from './utils.js'; import { idle } from './idle.js'; import { envs } from './env.js'; +import type { NangoProps } from '@nangohq/types'; const MEMORY_WARNING_PERCENTAGE_THRESHOLD = 75; diff --git a/packages/shared/lib/sdk/sync.integration.test.ts b/packages/runner/lib/sdk/sdk.integration.test.ts similarity index 83% rename from packages/shared/lib/sdk/sync.integration.test.ts rename to packages/runner/lib/sdk/sdk.integration.test.ts index cc85b45f9ff..045c0a55898 100644 --- a/packages/shared/lib/sdk/sync.integration.test.ts +++ b/packages/runner/lib/sdk/sdk.integration.test.ts @@ -1,14 +1,13 @@ import { expect, describe, it, beforeAll } from 'vitest'; import { multipleMigrations } from '@nangohq/database'; -import type { Connection } from '../models/Connection.js'; -import type { NangoProps } from './sync.js'; -import { NangoAction } from './sync.js'; -import connectionService from '../services/connection.service.js'; -import environmentService from '../services/environment.service.js'; -import { createConnectionSeeds } from '../seeders/connection.seeder.js'; -import { createConfigSeeds } from '../seeders/config.seeder.js'; -import { createEnvironmentSeed } from '../seeders/environment.seeder.js'; -import type { DBEnvironment, DBSyncConfig } from '@nangohq/types'; +import type { Connection } from '@nangohq/shared/lib/models/Connection.js'; +import connectionService from '@nangohq/shared/lib/services/connection.service.js'; +import environmentService from '@nangohq/shared/lib/services/environment.service.js'; +import { createConnectionSeeds } from '@nangohq/shared/lib/seeders/connection.seeder.js'; +import { createConfigSeeds } from '@nangohq/shared/lib/seeders/config.seeder.js'; +import { createEnvironmentSeed } from '@nangohq/shared/lib/seeders/environment.seeder.js'; +import type { DBEnvironment, DBSyncConfig, NangoProps } from '@nangohq/types'; +import { NangoActionRunner } from './sdk.js'; describe('Connection service integration tests', () => { let env: DBEnvironment; @@ -60,7 +59,7 @@ describe('Connection service integration tests', () => { endUser: null }; - const nango = new NangoAction(nangoProps); + const nango = new NangoActionRunner(nangoProps); // @ts-expect-error we are overriding a private method here nango.nango.getConnection = async (providerConfigKey: string, connectionId: string) => { diff --git a/packages/runner/lib/sdk/sdk.ts b/packages/runner/lib/sdk/sdk.ts new file mode 100644 index 00000000000..8aa0b5842e1 --- /dev/null +++ b/packages/runner/lib/sdk/sdk.ts @@ -0,0 +1,464 @@ +import https from 'node:https'; +import type { AxiosInstance, AxiosResponse } from 'axios'; +import axios, { AxiosError } from 'axios'; + +import { getUserAgent, Nango } from '@nangohq/node'; +import type { ProxyConfiguration } from '@nangohq/runner-sdk'; +import { InvalidRecordSDKError, NangoActionBase, NangoSyncBase } from '@nangohq/runner-sdk'; +import { getPersistAPIUrl, proxyService, redactHeaders, redactURL } from '@nangohq/shared'; +import type { MessageRowInsert, NangoProps, UserLogParameters } from '@nangohq/types'; +import { + getLogger, + httpRetryStrategy, + isTest, + MAX_LOG_PAYLOAD, + metrics, + retryWithBackoff, + stringifyAndTruncateValue, + stringifyObject, + truncateJson +} from '@nangohq/utils'; + +const logger = getLogger('SDK'); + +export const oldLevelToNewLevel = { + debug: 'debug', + info: 'info', + warn: 'warn', + error: 'error', + verbose: 'debug', + silly: 'debug', + http: 'info' +} as const; + +export const defaultPersistApi = axios.create({ + baseURL: getPersistAPIUrl(), + httpsAgent: new https.Agent({ keepAlive: true }), + headers: { + 'User-Agent': getUserAgent('sdk') + }, + validateStatus: (_status) => { + return true; + } +}); + +const RECORDS_VALIDATION_SAMPLE = 5; + +/** + * Action SDK + */ +export class NangoActionRunner extends NangoActionBase { + nango: Nango; + protected persistApi: AxiosInstance; + + constructor(props: NangoProps, runnerProps?: { persistApi: AxiosInstance }) { + super(props); + this.persistApi = runnerProps?.persistApi || defaultPersistApi; + + this.nango = new Nango( + { isSync: false, dryRun: isTest, ...props }, + { + interceptors: { response: { onFulfilled: this.logAPICall.bind(this) } } + } + ); + + if (!this.activityLogId) throw new Error('Parameter activityLogId is required when not in dryRun'); + if (!this.environmentId) throw new Error('Parameter environmentId is required when not in dryRun'); + if (!this.nangoConnectionId) throw new Error('Parameter nangoConnectionId is required when not in dryRun'); + if (!this.syncConfig) throw new Error('Parameter syncConfig is required when not in dryRun'); + } + + public override async proxy(config: ProxyConfiguration): Promise> { + this.throwIfAborted(); + if (!config.method) { + config.method = 'GET'; + } + + const { connectionId, providerConfigKey } = config; + const connection = await this.getConnection(providerConfigKey, connectionId); + if (!connection) { + throw new Error(`Connection not found using the provider config key ${this.providerConfigKey} and connection id ${this.connectionId}`); + } + + const proxyConfig = this.proxyConfig(config); + + const { response, logs } = await proxyService.route(proxyConfig, { + existingActivityLogId: this.activityLogId as string, + connection, + providerName: this.provider as string + }); + + // We batch save, since we have buffered the createdAt it shouldn't impact order + await Promise.all( + logs.map(async (log) => { + if (log.level === 'debug') { + return; + } + await this.sendLogToPersist(log); + }) + ); + + if (response instanceof Error) { + throw response; + } + + return response; + } + + public override async log(...args: [...any]): Promise { + this.throwIfAborted(); + if (args.length === 0) { + return; + } + + const lastArg = args[args.length - 1]; + const isUserDefinedLevel = (object: UserLogParameters): boolean => { + return lastArg && typeof lastArg === 'object' && 'level' in object; + }; + const userDefinedLevel: UserLogParameters | undefined = isUserDefinedLevel(lastArg) ? lastArg : undefined; + + if (userDefinedLevel) { + args.pop(); + } + + const level = userDefinedLevel?.level ?? 'info'; + const [message, payload] = args; + + // arrays are not supported in the log meta, so we convert them to objects + const meta = Array.isArray(payload) ? Object.fromEntries(payload.map((e, i) => [i, e])) : payload || null; + + await this.sendLogToPersist({ + type: 'log', + level: oldLevelToNewLevel[level], + source: 'user', + message: stringifyAndTruncateValue(message), + meta, + createdAt: new Date().toISOString(), + environmentId: this.environmentId + }); + } + + public triggerSync(providerConfigKey: string, connectionId: string, syncName: string, fullResync?: boolean): Promise { + this.throwIfAborted(); + return this.nango.triggerSync(providerConfigKey, [syncName], connectionId, fullResync); + } + + private async sendLogToPersist(log: MessageRowInsert) { + let response: AxiosResponse; + try { + response = await retryWithBackoff( + async () => { + let data = stringifyObject({ activityLogId: this.activityLogId, log }); + + // We try to keep log object under an acceptable size, before reaching network + // The idea is to always log something instead of silently crashing without overloading persist + if (data.length > MAX_LOG_PAYLOAD) { + log.message += ` ... (truncated, payload was too large)`; + // Truncating can remove mandatory field so we only try to truncate meta + if (log.meta) { + data = stringifyObject({ + activityLogId: this.activityLogId, + log: { ...log, meta: truncateJson(log.meta) as MessageRowInsert['meta'] } + }); + } + } + + return await this.persistApi({ + method: 'POST', + url: `/environment/${this.environmentId}/log`, + headers: { + Authorization: `Bearer ${this.nango.secretKey}`, + 'Content-Type': 'application/json' + }, + data + }); + }, + { retry: httpRetryStrategy } + ); + } catch (err) { + logger.error('Failed to log to persist, due to an internal error', err instanceof AxiosError ? err.code : err); + // We don't want to block a sync because logging failed, so we fail silently until we have a way to report error + // TODO: find a way to report that + return; + } + + if (response.status > 299) { + logger.error( + `Request to persist API (log) failed: errorCode=${response.status} response='${JSON.stringify(response.data)}' log=${JSON.stringify(log)}`, + this.stringify() + ); + throw new Error(`Failed to log: ${JSON.stringify(response.data)}`); + } + } + + private logAPICall(res: AxiosResponse): AxiosResponse { + if (!res.config.url) { + return res; + } + + // We compte on the fly because connection's credentials can change during a single run + // We could further optimize this and cache it when the memoizedConnection is updated + const valuesToFilter: string[] = [ + ...Array.from(this.memoizedConnections.values()).reduce((acc, conn) => { + if (!conn) { + return acc; + } + acc.push(...Object.values(conn.connection.credentials)); + return acc; + }, []), + this.nango.secretKey + ]; + + const method = res.config.method?.toLocaleUpperCase(); // axios put it in lowercase; + void this.log( + `${method} ${res.config.url}`, + { + type: 'http', + request: { + method: method, + url: redactURL({ url: res.config.url, valuesToFilter }), + headers: redactHeaders({ headers: res.config.headers, valuesToFilter }) + }, + response: { + code: res.status, + headers: redactHeaders({ headers: res.headers, valuesToFilter }) + } + }, + { level: res.status > 299 ? 'error' : 'info' } + ); + return res; + } +} + +/** + * Sync SDK + */ +export class NangoSyncRunner extends NangoSyncBase { + nango: Nango; + + protected persistApi: AxiosInstance; + private batchSize = 1000; + + constructor(props: NangoProps, runnerProps?: { persistApi?: AxiosInstance }) { + super(props); + + this.persistApi = runnerProps?.persistApi || defaultPersistApi; + this.nango = new Nango( + { isSync: true, dryRun: isTest, ...props }, + { + interceptors: { response: { onFulfilled: this.logAPICall.bind(this) } } + } + ); + + if (!this.syncId) throw new Error('Parameter syncId is required when not in dryRun'); + if (!this.syncJobId) throw new Error('Parameter syncJobId is required when not in dryRun'); + } + + // Can't double extends + proxy = NangoActionRunner['prototype']['proxy']; + log = NangoActionRunner['prototype']['log']; + triggerSync = NangoActionRunner['prototype']['triggerSync']; + sendLogToPersist = NangoActionRunner['prototype']['sendLogToPersist']; + logAPICall = NangoActionRunner['prototype']['logAPICall']; + + public async batchSave(results: T[], model: string) { + this.throwIfAborted(); + if (!results || results.length === 0) { + return true; + } + + // Validate records + const hasErrors = this.validateRecords(model, results); + + if (hasErrors.length > 0) { + metrics.increment(metrics.Types.RUNNER_INVALID_SYNCS_RECORDS, hasErrors.length); + this.log('Invalid record payload. Use `--validation` option to see the details', { level: 'warn' }); + if (this.runnerFlags?.validateSyncRecords) { + throw new InvalidRecordSDKError({ ...hasErrors[0], model }); + } + + const sampled = hasErrors.length > RECORDS_VALIDATION_SAMPLE; + const sample = sampled ? hasErrors.slice(0, RECORDS_VALIDATION_SAMPLE) : hasErrors; + if (sampled) { + await this.log(`Invalid records: ${hasErrors.length} failed ${sampled ? `(sampled to ${RECORDS_VALIDATION_SAMPLE})` : ''}`, { level: 'warn' }); + } + await Promise.all( + sample.map((log) => { + return this.log(`Invalid record payload`, { ...log, model }, { level: 'warn' }); + }) + ); + } + + for (let i = 0; i < results.length; i += this.batchSize) { + const batch = results.slice(i, i + this.batchSize); + let response: AxiosResponse; + try { + response = await retryWithBackoff( + () => { + return this.persistApi({ + method: 'POST', + url: `/environment/${this.environmentId}/connection/${this.nangoConnectionId}/sync/${this.syncId}/job/${this.syncJobId}/records`, + headers: { + Authorization: `Bearer ${this.nango.secretKey}` + }, + data: { + model, + records: batch, + providerConfigKey: this.providerConfigKey, + connectionId: this.connectionId, + activityLogId: this.activityLogId + } + }); + }, + { retry: httpRetryStrategy } + ); + } catch (err) { + logger.error('Internal error', err instanceof AxiosError ? err.code : err); + throw new Error('Failed to save records due to an internal error', { cause: err }); + } + + if (response.status > 299) { + logger.error( + `Request to persist API (batchSave) failed: errorCode=${response.status} response='${JSON.stringify(response.data)}'`, + this.stringify() + ); + + if (response.status === 400) { + throw new Error( + `Records invalid format. Please make sure you are sending an array of objects that each contain an 'id' property with type string` + ); + } else { + const message = 'error' in response.data && 'message' in response.data.error ? response.data.error.message : JSON.stringify(response.data); + throw new Error(message); + } + } + } + return true; + } + + public async batchDelete(results: T[], model: string) { + this.throwIfAborted(); + if (!results || results.length === 0) { + return true; + } + + for (let i = 0; i < results.length; i += this.batchSize) { + const batch = results.slice(i, i + this.batchSize); + let response: AxiosResponse; + try { + response = await retryWithBackoff( + async () => { + return await this.persistApi({ + method: 'DELETE', + url: `/environment/${this.environmentId}/connection/${this.nangoConnectionId}/sync/${this.syncId}/job/${this.syncJobId}/records`, + headers: { + Authorization: `Bearer ${this.nango.secretKey}` + }, + data: { + model, + records: batch, + providerConfigKey: this.providerConfigKey, + connectionId: this.connectionId, + activityLogId: this.activityLogId + } + }); + }, + { retry: httpRetryStrategy } + ); + } catch (err) { + logger.error('Internal error', err instanceof AxiosError ? err.code : err); + throw new Error('Failed to delete records due to an internal error', { cause: err }); + } + + if (response.status > 299) { + logger.error( + `Request to persist API (batchDelete) failed: errorCode=${response.status} response='${JSON.stringify(response.data)}'`, + this.stringify() + ); + const message = 'error' in response.data && 'message' in response.data.error ? response.data.error.message : JSON.stringify(response.data); + throw new Error(message); + } + } + + return true; + } + + public async batchUpdate(results: T[], model: string) { + this.throwIfAborted(); + if (!results || results.length === 0) { + return true; + } + + for (let i = 0; i < results.length; i += this.batchSize) { + const batch = results.slice(i, i + this.batchSize); + let response: AxiosResponse; + try { + response = await retryWithBackoff( + async () => { + return await this.persistApi({ + method: 'PUT', + url: `/environment/${this.environmentId}/connection/${this.nangoConnectionId}/sync/${this.syncId}/job/${this.syncJobId}/records`, + headers: { + Authorization: `Bearer ${this.nango.secretKey}` + }, + data: { + model, + records: batch, + providerConfigKey: this.providerConfigKey, + connectionId: this.connectionId, + activityLogId: this.activityLogId + } + }); + }, + { retry: httpRetryStrategy } + ); + } catch (err) { + logger.error('Internal error', err instanceof AxiosError ? err.code : err); + throw new Error('Failed to update records due to an internal error', { cause: err }); + } + + if (response.status > 299) { + logger.error( + `Request to persist API (batchUpdate) failed: errorCode=${response.status} response='${JSON.stringify(response.data)}'`, + this.stringify() + ); + const message = 'error' in response.data && 'message' in response.data.error ? response.data.error.message : JSON.stringify(response.data); + throw new Error(message); + } + } + return true; + } +} + +const TELEMETRY_ALLOWED_METHODS: (keyof NangoSyncBase)[] = [ + 'batchDelete', + 'batchSave', + 'batchSend', + 'getConnection', + 'getEnvironmentVariables', + 'getMetadata', + 'proxy', + 'log', + 'triggerAction', + 'triggerSync' +]; + +/** + * @internal + * + * This function will enable tracing on the SDK + * It has been split from the actual code to avoid making the code too dirty and to easily enable/disable tracing if there is an issue with it + */ +export function instrumentSDK(rawNango: NangoActionBase | NangoSyncBase) { + return new Proxy(rawNango, { + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters + get(target: T, propKey: K) { + // Method name is not matching the allowList we don't do anything else + if (!TELEMETRY_ALLOWED_METHODS.includes(propKey)) { + return target[propKey]; + } + + return metrics.time(`${metrics.Types.RUNNER_SDK}.${propKey}` as any, (target[propKey] as any).bind(target)); + } + }); +} diff --git a/packages/shared/lib/sdk/sync.unit.test.ts b/packages/runner/lib/sdk/sdk.unit.test.ts similarity index 63% rename from packages/shared/lib/sdk/sync.unit.test.ts rename to packages/runner/lib/sdk/sdk.unit.test.ts index cb00c89a0f6..b6ba8bcb2ff 100644 --- a/packages/shared/lib/sdk/sync.unit.test.ts +++ b/packages/runner/lib/sdk/sdk.unit.test.ts @@ -1,17 +1,11 @@ /* eslint-disable @typescript-eslint/unbound-method */ import { Nango } from '@nangohq/node'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; -import { mockErrorManagerReport } from '../utils/error.manager.mocks.js'; -import type { Config } from '../models/index.js'; -import type { CursorPagination, DBSyncConfig, LinkPagination, OffsetPagination, Pagination, Provider } from '@nangohq/types'; -import configService from '../services/config.service.js'; -import * as providerService from '../services/providers.js'; -import type { NangoProps } from './sync.js'; -import { NangoAction, NangoSync } from './sync.js'; -import { isValidHttpUrl } from '../utils/utils.js'; -import proxyService from '../services/proxy.service.js'; +import { isValidHttpUrl, proxyService } from '@nangohq/shared'; +import type { CursorPagination, DBSyncConfig, LinkPagination, NangoProps, OffsetPagination, Pagination, Provider } from '@nangohq/types'; import type { AxiosResponse } from 'axios'; -import { NangoError } from '../utils/error.js'; +import { NangoActionRunner, NangoSyncRunner } from './sdk.js'; +import { AbortedSDKError, InvalidRecordSDKError } from '@nangohq/runner-sdk'; const nangoProps: NangoProps = { scriptType: 'sync', @@ -19,7 +13,6 @@ const nangoProps: NangoProps = { providerConfigKey: 'github', provider: 'github', connectionId: 'connection-1', - dryRun: false, activityLogId: '1', team: { id: 1, @@ -39,10 +32,10 @@ const nangoProps: NangoProps = { }; describe('cache', () => { - let nangoAction: NangoAction; + let nangoAction: NangoActionRunner; let nango: Nango; beforeEach(async () => { - nangoAction = new NangoAction({ + nangoAction = new NangoActionRunner({ ...nangoProps }); nango = new Nango({ secretKey: '***' }); @@ -52,6 +45,7 @@ describe('cache', () => { nodeClient.prototype.getIntegration = vi.fn().mockReturnValue({ data: { provider: 'github' } }); vi.spyOn(proxyService, 'route').mockImplementation(() => Promise.resolve({ response: {} as AxiosResponse, logs: [] })); }); + afterEach(() => { vi.clearAllMocks(); }); @@ -123,19 +117,19 @@ describe('Pagination', () => { const paginationConfigs = [cursorPagination, offsetPagination, linkPagination]; - let nangoAction: NangoAction; - let nango: Nango; + let nangoAction: NangoActionRunner; - beforeEach(() => { - const config: any = { + beforeEach(async () => { + const config: NangoProps = { + ...nangoProps, secretKey: 'encrypted', - serverUrl: 'https://example.com', providerConfigKey, - connectionId, - dryRun: true + connectionId }; - nangoAction = new NangoAction(config); - nango = new Nango({ secretKey: config.secretKey }); + nangoAction = new NangoActionRunner(config); + + const nodeClient = (await import('@nangohq/node')).Nango; + nodeClient.prototype.getConnection = vi.fn().mockReturnValue({ credentials: {} }); }); afterEach(() => { @@ -151,50 +145,44 @@ describe('Pagination', () => { token_url: '', docs: '' }; - (await import('@nangohq/node')).Nango.prototype.getIntegration = vi.fn().mockReturnValue({ config: { provider: 'github' } }); - vi.spyOn(providerService, 'getProvider').mockImplementation(() => provider); + vi.spyOn(await import('@nangohq/providers'), 'getProvider').mockImplementation(() => provider); const expectedErrorMessage = 'There was no pagination configuration for this integration or configuration passed in'; await expect(() => nangoAction.paginate({ endpoint: '' }).next()).rejects.toThrowError(expectedErrorMessage); }); it('Sends pagination params in body for POST HTTP method', async () => { - stubProviderTemplate(cursorPagination); - mockErrorManagerReport(); - - vi.spyOn(configService, 'getProviderConfig').mockImplementation(() => { - return Promise.resolve({} as Config); - }); + await stubProviderTemplate(cursorPagination); - // TODO: mock to return at least one more page to check that cursor is passed in body too - (await import('@nangohq/node')).Nango.prototype.proxy = vi.fn().mockReturnValue({ data: { issues: [] } }); - (await import('@nangohq/node')).Nango.prototype.getIntegration = vi.fn().mockReturnValue({ config: { provider: 'github' } }); - (await import('@nangohq/node')).Nango.prototype.getConnection = vi.fn().mockReturnValue({ credentials: {} }); + const spy = vi.spyOn(proxyService, 'route').mockReturnValueOnce(Promise.resolve({ logs: [], response: { data: { issues: [] } } as AxiosResponse })); const endpoint = '/issues'; await nangoAction.paginate({ endpoint, method: 'POST', paginate: { limit: 2 }, connectionId: 'abc' }).next(); - expect(nango.proxy).toHaveBeenCalledWith({ - method: 'POST', - endpoint, - headers: { - 'user-agent': expect.any(String) - }, - data: { limit: 2 }, - paginate: { limit: 2 }, - connectionId: 'abc', - providerConfigKey: 'github' - }); + expect(spy).toHaveBeenCalledWith( + expect.objectContaining({ + method: 'POST', + endpoint, + headers: { + 'user-agent': expect.any(String) + }, + data: { limit: 2 }, + paginate: { limit: 2 }, + connectionId: 'abc', + providerConfigKey: 'github' + }), + expect.objectContaining({}) + ); }); it('Overrides template pagination params with ones passed in the proxy config', async () => { - stubProviderTemplate(cursorPagination); + await stubProviderTemplate(cursorPagination); - (await import('@nangohq/node')).Nango.prototype.proxy = vi - .fn() - .mockReturnValueOnce({ data: { issues: [{}, {}, {}] } }) - .mockReturnValueOnce({ data: { issues: [] } }); + const spy = vi + .spyOn(proxyService, 'route') + .mockReturnValueOnce(Promise.resolve({ logs: [], response: { data: { issues: [{}, {}, {}] } } as AxiosResponse })) + .mockReturnValueOnce(Promise.resolve({ logs: [], response: { data: { issues: [] } } as AxiosResponse })); const endpoint = '/issues'; const paginationConfigOverride: OffsetPagination = { @@ -210,29 +198,32 @@ describe('Pagination', () => { expect(batch.length).toBe(3); } - expect(nango.proxy).toHaveBeenLastCalledWith({ - method: 'GET', - endpoint, - headers: { - 'user-agent': expect.any(String) + expect(spy).toHaveBeenLastCalledWith( + { + method: 'GET', + endpoint, + headers: { + 'user-agent': expect.any(String) + }, + params: { offset: '3', per_page: 3 }, + paginate: paginationConfigOverride, + providerConfigKey, + connectionId }, - params: { offset: '3', per_page: 3 }, - paginate: paginationConfigOverride, - providerConfigKey, - connectionId - }); + { connection: { credentials: {} }, existingActivityLogId: '1', providerName: 'github' } + ); }); it('Paginates using offset', async () => { - stubProviderTemplate(offsetPagination); + await stubProviderTemplate(offsetPagination); const firstBatch: any[] = [{ id: 1 }, { id: 2 }, { id: 3 }]; const secondBatch: any[] = [{ id: 4 }, { id: 5 }, { id: 6 }]; - (await import('@nangohq/node')).Nango.prototype.proxy = vi - .fn() - .mockReturnValueOnce({ data: { issues: firstBatch } }) - .mockReturnValueOnce({ data: { issues: secondBatch } }) - .mockReturnValueOnce({ data: { issues: [] } }); + + vi.spyOn(proxyService, 'route') + .mockReturnValueOnce(Promise.resolve({ logs: [], response: { data: { issues: firstBatch } } as AxiosResponse })) + .mockReturnValueOnce(Promise.resolve({ logs: [], response: { data: { issues: secondBatch } } as AxiosResponse })) + .mockReturnValueOnce(Promise.resolve({ logs: [], response: { data: { issues: [] } } as AxiosResponse })); const endpoint = '/issues'; @@ -249,30 +240,26 @@ describe('Pagination', () => { }); it('Paginates using cursor', async () => { - stubProviderTemplate(cursorPagination); + await stubProviderTemplate(cursorPagination); const firstBatch: any[] = [{ id: 1 }, { id: 2 }, { id: 3 }]; const secondBatch: any[] = [{ id: 4 }, { id: 5 }, { id: 6 }]; const thirdBatch: any[] = [{ id: 7 }, { id: 8 }, { id: 9 }]; - (await import('@nangohq/node')).Nango.prototype.proxy = vi - .fn() - .mockReturnValueOnce({ - data: { - issues: firstBatch, - metadata: { - next_cursor: '2' - } - } - }) - .mockReturnValueOnce({ - data: { - issues: secondBatch, - metadata: { - next_cursor: '2' - } - } - }) - .mockReturnValueOnce({ data: { issues: thirdBatch } }); + + vi.spyOn(proxyService, 'route') + .mockReturnValueOnce( + Promise.resolve({ + logs: [], + response: { data: { issues: firstBatch, metadata: { next_cursor: '2' } } } as AxiosResponse + }) + ) + .mockReturnValueOnce( + Promise.resolve({ + logs: [], + response: { data: { issues: secondBatch, metadata: { next_cursor: '2' } } } as AxiosResponse + }) + ) + .mockReturnValueOnce(Promise.resolve({ logs: [], response: { data: { issues: thirdBatch } } as AxiosResponse })); const endpoint = '/issues'; @@ -289,17 +276,16 @@ describe('Pagination', () => { }); it('Stops pagination if cursor is empty', async () => { - stubProviderTemplate(cursorPagination); + await stubProviderTemplate(cursorPagination); const onlyBatch: any[] = [{ id: 1 }, { id: 2 }, { id: 3 }]; - (await import('@nangohq/node')).Nango.prototype.proxy = vi.fn().mockReturnValueOnce({ - data: { - issues: onlyBatch, - metadata: { - next_cursor: '' - } - } - }); + + vi.spyOn(proxyService, 'route').mockReturnValueOnce( + Promise.resolve({ + logs: [], + response: { data: { issues: onlyBatch, metadata: { next_cursor: '' } } } as AxiosResponse + }) + ); const endpoint = '/issues'; @@ -316,29 +302,24 @@ describe('Pagination', () => { it.each(paginationConfigs)( 'Extracts records from nested body param for $type pagination type', async (paginationConfig: CursorPagination | OffsetPagination | LinkPagination) => { - stubProviderTemplate(paginationConfig); + await stubProviderTemplate(paginationConfig); const firstBatch: any[] = [{ id: 1 }, { id: 2 }, { id: 3 }]; const emptyBatch: any[] = []; - (await import('@nangohq/node')).Nango.prototype.proxy = vi - .fn() - .mockReturnValueOnce({ - data: { - issues: firstBatch, - metadata: { - next_cursor: '' - } - } - }) - .mockReturnValueOnce({ - data: { - issues: emptyBatch, - metadata: { - next_cursor: '' - } - } - }); + vi.spyOn(proxyService, 'route') + .mockReturnValueOnce( + Promise.resolve({ + logs: [], + response: { data: { issues: firstBatch, metadata: { next_cursor: '' } } } as AxiosResponse + }) + ) + .mockReturnValueOnce( + Promise.resolve({ + logs: [], + response: { data: { issues: emptyBatch, metadata: { next_cursor: '' } } } as AxiosResponse + }) + ); const endpoint = '/issues'; @@ -358,30 +339,32 @@ describe('Pagination', () => { ['https://api.gihub.com/issues?page=2', 'https://api.gihub.com/issues?page=3'], ['/issues?page=2', '/issues?page=3'] ])('Paginates using next URL/path %s from body', async (nextUrlOrPathValue, anotherNextUrlOrPathValue) => { - stubProviderTemplate(linkPagination); + await stubProviderTemplate(linkPagination); const firstBatch: any[] = [{ id: 1 }, { id: 2 }, { id: 3 }]; const secondBatch: any[] = [{ id: 4 }, { id: 5 }, { id: 6 }]; const thirdBatch: any[] = [{ id: 7 }, { id: 8 }, { id: 9 }]; - (await import('@nangohq/node')).Nango.prototype.proxy = vi - .fn() - .mockReturnValueOnce({ - data: { - issues: firstBatch, - metadata: { - next_cursor: nextUrlOrPathValue - } - } - }) - .mockReturnValueOnce({ - data: { - issues: secondBatch, - metadata: { - next_cursor: anotherNextUrlOrPathValue - } - } - }) - .mockReturnValueOnce({ data: { issues: thirdBatch } }); + + const spy = vi + .spyOn(proxyService, 'route') + .mockReturnValueOnce( + Promise.resolve({ + logs: [], + response: { data: { issues: firstBatch, metadata: { next_cursor: nextUrlOrPathValue } } } as AxiosResponse + }) + ) + .mockReturnValueOnce( + Promise.resolve({ + logs: [], + response: { data: { issues: secondBatch, metadata: { next_cursor: anotherNextUrlOrPathValue } } } as AxiosResponse + }) + ) + .mockReturnValueOnce( + Promise.resolve({ + logs: [], + response: { data: { issues: thirdBatch } } as AxiosResponse + }) + ); const endpoint = '/issues'; @@ -402,16 +385,21 @@ describe('Pagination', () => { } expect(actualRecords).toStrictEqual(expectedRecords); - expect(nango.proxy).toHaveBeenCalledWith( + expect(spy).toHaveBeenNthCalledWith( + 3, expect.objectContaining({ endpoint: expectedEndpoint + }), + expect.objectContaining({ + providerName: 'github' }) ); }); - const stubProviderTemplate = (paginationConfig: Pagination) => { + const stubProviderTemplate = async (paginationConfig: Pagination) => { const provider: Provider = buildTemplate(paginationConfig); - vi.spyOn(providerService, 'getProvider').mockImplementation(() => provider); + + vi.spyOn(await import('@nangohq/providers'), 'getProvider').mockImplementation(() => provider); }; const buildTemplate = (paginationConfig: Pagination): Provider => { @@ -428,9 +416,8 @@ describe('Pagination', () => { describe('batchSave', () => { it('should validate records with json schema', async () => { - const nango = new NangoSync({ + const nango = new NangoSyncRunner({ ...nangoProps, - dryRun: true, runnerFlags: { validateSyncRecords: true } as any, syncConfig: { models_json_schema: { @@ -439,25 +426,25 @@ describe('batchSave', () => { } as any }); - await expect(async () => await nango.batchSave([{ foo: 'bar' }], 'Test')).rejects.toThrow(new NangoError(`invalid_sync_record`)); + await expect(async () => await nango.batchSave([{ foo: 'bar' }], 'Test')).rejects.toThrow(new InvalidRecordSDKError()); }); }); describe('Log', () => { it('should enforce activityLogId when not in dryRun', () => { expect(() => { - new NangoAction({ ...nangoProps, activityLogId: undefined }); + new NangoActionRunner({ ...nangoProps, activityLogId: undefined }); }).toThrowError(new Error('Parameter activityLogId is required when not in dryRun')); }); it('should not fail on null', async () => { - const nangoAction = new NangoAction({ ...nangoProps, dryRun: true }); + const nangoAction = new NangoActionRunner({ ...nangoProps }); await nangoAction.log(null); }); it('should allow level', async () => { const mock = vi.fn(() => ({ response: { status: 200 } })); - const nangoAction = new NangoAction({ ...nangoProps }, { persistApi: mock as any }); + const nangoAction = new NangoActionRunner({ ...nangoProps }, { persistApi: mock as any }); await nangoAction.log('hello', { level: 'error' }); @@ -485,27 +472,26 @@ describe('Log', () => { }); it('should enforce type: log message + object + level', async () => { - const nangoAction = new NangoAction({ ...nangoProps, dryRun: true }); - // @ts-expect-error Level is wrong on purpose, if it's not breaking anymore the type is broken + const nangoAction = new NangoActionRunner({ ...nangoProps }); await nangoAction.log('hello', { foo: 'bar' }, { level: 'foobar' }); }); it('should enforce type: log message +level', async () => { - const nangoAction = new NangoAction({ ...nangoProps, dryRun: true }); - // @ts-expect-error Level is wrong on purpose, if it's not breaking anymore the type is broken + const nangoAction = new NangoActionRunner({ ...nangoProps }); await nangoAction.log('hello', { level: 'foobar' }); }); it('should enforce type: log message + object', async () => { - const nangoAction = new NangoAction({ ...nangoProps, dryRun: true }); + const nangoAction = new NangoActionRunner({ ...nangoProps }); await nangoAction.log('hello', { foo: 'bar' }); }); }); + describe('Aborted script', () => { it('show throw', () => { const ac = new AbortController(); - const nango = new NangoSync({ ...nangoProps, abortSignal: ac.signal }); + const nango = new NangoSyncRunner({ ...nangoProps, abortSignal: ac.signal }); ac.abort(); - expect(nango.log('hello')).rejects.toThrowError(new Error('The script was aborted')); + expect(nango.log('hello')).rejects.toThrowError(new AbortedSDKError()); }); }); diff --git a/packages/runner/lib/server.ts b/packages/runner/lib/server.ts index 290abdd8d16..f1c60e3d520 100644 --- a/packages/runner/lib/server.ts +++ b/packages/runner/lib/server.ts @@ -3,7 +3,6 @@ import * as trpcExpress from '@trpc/server/adapters/express'; import express from 'express'; import type { Request, Response, NextFunction } from 'express'; import timeout from 'connect-timeout'; -import type { NangoProps } from '@nangohq/shared'; import { RunnerMonitor } from './monitor.js'; import { exec } from './exec.js'; import { abort } from './abort.js'; @@ -11,6 +10,7 @@ import superjson from 'superjson'; import { httpFetch, logger } from './utils.js'; import { abortControllers } from './state.js'; import { runnerId, persistServiceUrl, jobsServiceUrl, heartbeatIntervalMs } from './env.js'; +import type { NangoProps } from '@nangohq/types'; export const t = initTRPC.create({ transformer: superjson diff --git a/packages/runner/package.json b/packages/runner/package.json index 6d5ed9739e0..b783db43445 100644 --- a/packages/runner/package.json +++ b/packages/runner/package.json @@ -18,7 +18,10 @@ }, "license": "SEE LICENSE IN LICENSE FILE IN GIT REPOSITORY", "dependencies": { + "@nangohq/node": "file:../node-client", + "@nangohq/runner-sdk": "file:../runner-sdk", "@nangohq/shared": "file:../shared", + "@nangohq/providers": "file:../providers", "@nangohq/utils": "file:../utils", "@trpc/client": "^10.45.1", "@trpc/server": "^10.45.1", @@ -34,6 +37,7 @@ }, "devDependencies": { "@nangohq/types": "file:../types", + "@nangohq/database": "file:../database", "@types/connect-timeout": "0.0.39", "@types/node": "20.12.2", "typescript": "5.7.3", diff --git a/packages/runner/tsconfig.json b/packages/runner/tsconfig.json index f5d019a9a1f..dd1a34fae6d 100644 --- a/packages/runner/tsconfig.json +++ b/packages/runner/tsconfig.json @@ -5,9 +5,21 @@ "outDir": "dist" }, "references": [ + { + "path": "../database" + }, + { + "path": "../node-client" + }, + { + "path": "../runner-sdk" + }, { "path": "../shared" }, + { + "path": "../providers" + }, { "path": "../types" }, diff --git a/packages/server/lib/controllers/connection/connectionId/getConnection.ts b/packages/server/lib/controllers/connection/connectionId/getConnection.ts index 0521749fbe1..5990c2a54b7 100644 --- a/packages/server/lib/controllers/connection/connectionId/getConnection.ts +++ b/packages/server/lib/controllers/connection/connectionId/getConnection.ts @@ -87,7 +87,6 @@ export const getPublicConnection = asyncWrapper(async (req, if (connection.credentials.raw && connection.credentials.raw['refresh_token']) { const rawCreds = { ...connection.credentials.raw }; // Properties from 'raw' are not mutable so we need to create a new object. - // eslint-disable-next-line @typescript-eslint/no-dynamic-delete const { refresh_token, ...rest } = rawCreds; connection.credentials.raw = rest; diff --git a/packages/server/lib/controllers/v1/integrations/providerConfigKey/patchIntegration.ts b/packages/server/lib/controllers/v1/integrations/providerConfigKey/patchIntegration.ts index f01d82fd5fd..42c283bd8ae 100644 --- a/packages/server/lib/controllers/v1/integrations/providerConfigKey/patchIntegration.ts +++ b/packages/server/lib/controllers/v1/integrations/providerConfigKey/patchIntegration.ts @@ -120,7 +120,6 @@ export const patchIntegration = asyncWrapper(async (req, res) integration.custom = {}; } if (!body.webhookSecret) { - // eslint-disable-next-line @typescript-eslint/no-dynamic-delete delete integration.custom['webhookSecret']; } else { integration.custom['webhookSecret'] = body.webhookSecret; diff --git a/packages/server/lib/webhook/github-app-oauth-webhook-routing.ts b/packages/server/lib/webhook/github-app-oauth-webhook-routing.ts index 49ed9ece2ce..6cc1488ad6e 100644 --- a/packages/server/lib/webhook/github-app-oauth-webhook-routing.ts +++ b/packages/server/lib/webhook/github-app-oauth-webhook-routing.ts @@ -81,7 +81,7 @@ async function handleCreateWebhook(integration: ProviderConfig, body: any, logCo } const activityLogId = connection.connection_config['pendingLog']; - // eslint-disable-next-line @typescript-eslint/no-dynamic-delete + delete connection.connection_config['pendingLog']; const connectionConfig = { diff --git a/packages/server/nodemon.json b/packages/server/nodemon.json index 89b5e220295..3caee327ab0 100644 --- a/packages/server/nodemon.json +++ b/packages/server/nodemon.json @@ -8,7 +8,7 @@ "../webhooks/dist", "../keystore/dist", "../../.env", - "../shared/providers.yaml" + "../providers/providers.yaml" ], "ext": "js,ts,json", "ignore": ["src/**/*.test.ts"], diff --git a/packages/shared/lib/index.ts b/packages/shared/lib/index.ts index f8b73de8a60..5b03fda9ed0 100644 --- a/packages/shared/lib/index.ts +++ b/packages/shared/lib/index.ts @@ -47,9 +47,6 @@ export * from './utils/http.js'; export * from './utils/error.js'; export * from './constants.js'; -export * from './sdk/sync.js'; -export * from './sdk/dataValidation.js'; - export { getRoutes as getOtlpRoutes } from './otlp/otlp.js'; export { NANGO_VERSION } from './version.js'; diff --git a/packages/shared/lib/sdk/dataValidation.ts b/packages/shared/lib/sdk/dataValidation.ts deleted file mode 100644 index 7658ed0cd5b..00000000000 --- a/packages/shared/lib/sdk/dataValidation.ts +++ /dev/null @@ -1,73 +0,0 @@ -import type { ErrorObject, ValidateFunction } from 'ajv'; -import { Ajv } from 'ajv'; -import addFormats from 'ajv-formats'; -import type { JSONSchema7 } from 'json-schema'; - -export interface ValidateProps { - version: string; - input: unknown; - modelName: string | null | undefined; - jsonSchema: JSONSchema7 | undefined | null; -} - -let ajv: Ajv; -const cache = new Map>(); - -export function clearValidationCache() { - cache.clear(); -} - -export type ValidateDataError = ErrorObject | Error; - -export function validateData({ version, input, modelName, jsonSchema }: ValidateProps): true | ValidateDataError[] { - if (!jsonSchema) { - // For legacy reason, not all scripts have a jsonSchema - return true; - } - if (!modelName) { - if (input) { - // Unexpected input while the script expect nothing - return [{ instancePath: '', keyword: 'type', message: 'must be empty', params: {}, schemaPath: '#/type' }]; - } - // No expectation and no input, skip everything - return true; - } - if (!jsonSchema['definitions']![modelName]) { - // Unexpected input while the script expect nothing - return [new Error(`model_not_found_${modelName}`)]; - } - - if (!ajv) { - ajv = new Ajv({ allErrors: true, discriminator: true }); - addFormats(ajv); - } - - let validator: ValidateFunction; - try { - const key = `${modelName}-${version}`; - if (cache.has(key)) { - validator = cache.get(key)!; - } else { - // append all definitions and set current model name as the entry point - validator = ajv.compile({ ...(jsonSchema as any), ...(jsonSchema['definitions']![modelName] as any) }); - cache.set(key, validator); - } - - if (validator(input)) { - return true; - } - } catch (err) { - return [err instanceof Error ? err : new Error('failed_to_parse_json_schema')]; - } - - const bag: ErrorObject[] = []; - for (const error of validator.errors!) { - if (!error.message) { - continue; - } - - bag.push(error); - } - - return bag; -} diff --git a/packages/shared/lib/sdk/dataValidation.unit.test.ts b/packages/shared/lib/sdk/dataValidation.unit.test.ts deleted file mode 100644 index c3004618d42..00000000000 --- a/packages/shared/lib/sdk/dataValidation.unit.test.ts +++ /dev/null @@ -1,150 +0,0 @@ -import { beforeEach, describe, expect, it } from 'vitest'; -import { clearValidationCache, validateData } from './dataValidation.js'; - -describe('validateData', () => { - beforeEach(() => { - clearValidationCache(); - }); - - it('should skip if no json schema ', () => { - const val = validateData({ version: '1', input: { foo: 'bar' }, modelName: 'Test', jsonSchema: undefined }); - expect(val).toStrictEqual(true); - }); - - it('should return true if no error', () => { - const val = validateData({ - version: '1', - input: { foo: 'bar' }, - modelName: 'Test', - jsonSchema: { definitions: { Test: { type: 'object', properties: { foo: { type: 'string' } } } } } - }); - expect(val).toStrictEqual(true); - }); - - it('should return an error', () => { - const val = validateData({ - version: '1', - input: { foo: 'bar' }, - modelName: 'Test', - jsonSchema: { - definitions: { Test: { type: 'object', properties: { foo: { type: 'number' } }, required: ['foo'], additionalProperties: false } } - } - }); - expect(val).toStrictEqual([ - { instancePath: '/foo', keyword: 'type', message: 'must be number', params: { type: 'number' }, schemaPath: '#/properties/foo/type' } - ]); - }); - - it('should support ref', () => { - const val = validateData({ - version: '1', - input: { ref: { id: 'bar' } }, - modelName: 'Test1', - jsonSchema: { - definitions: { - Test1: { type: 'object', properties: { ref: { $ref: '#/definitions/Test2' } }, required: ['ref'], additionalProperties: false }, - Test2: { type: 'object', properties: { id: { type: 'string' } }, required: ['id'], additionalProperties: false } - } - } - }); - expect(val).toStrictEqual(true); - }); - - it('should support ref error', () => { - const val = validateData({ - version: '1', - input: { ref: { id: 1 } }, - modelName: 'Test1', - jsonSchema: { - definitions: { - Test1: { type: 'object', properties: { ref: { $ref: '#/definitions/Test2' } }, required: ['ref'], additionalProperties: false }, - Test2: { type: 'object', properties: { id: { type: 'string' } }, required: ['id'], additionalProperties: false } - } - } - }); - expect(val).toStrictEqual([ - { - instancePath: '/ref/id', - keyword: 'type', - message: 'must be string', - params: { type: 'string' }, - schemaPath: '#/definitions/Test2/properties/id/type' - } - ]); - }); - - it('should not throw if invalid json schema', () => { - const val = validateData({ - version: '1', - input: { foo: 'bar' }, - modelName: 'Test', - jsonSchema: { - definitions: { Test: { type: 'object', properties: { ref: { $ref: '#/definitions/NotFound' } } } } - } - }); - // Stringify because it's an exotic error object - expect(JSON.parse(JSON.stringify(val))).toStrictEqual([{ missingRef: '#/definitions/NotFound', missingSchema: '' }]); - }); - - it('should support exotic format', () => { - const val = validateData({ - version: '1', - input: { foo: 'bar' }, - modelName: 'Test', - jsonSchema: { - definitions: { Test: { type: 'object', properties: { date: { type: 'string', format: 'date-time' } } } } - } - }); - expect(val).toStrictEqual(true); - }); - - it('should handle empty input with model', () => { - const val = validateData({ - version: '1', - input: undefined, - modelName: 'Test', - jsonSchema: { - definitions: { Test: { type: 'object', properties: { date: { type: 'string', format: 'date-time' } } } } - } - }); - expect(val).toStrictEqual([ - { - instancePath: '', - keyword: 'type', - message: 'must be object', - params: { - type: 'object' - }, - schemaPath: '#/type' - } - ]); - }); - - it('should handle unexpected input', () => { - const val = validateData({ - version: '1', - input: '1', - modelName: undefined, - jsonSchema: { definitions: {} } - }); - expect(val).toStrictEqual([ - { - instancePath: '', - keyword: 'type', - message: 'must be empty', - params: {}, - schemaPath: '#/type' - } - ]); - }); - - it('should handle unknown modelName', () => { - const val = validateData({ - version: '1', - input: '1', - modelName: 'Test', - jsonSchema: { definitions: {} } - }); - expect(val).toStrictEqual([new Error(`model_not_found_Test`)]); - }); -}); diff --git a/packages/shared/lib/sdk/sync.ts b/packages/shared/lib/sdk/sync.ts deleted file mode 100644 index 030f63568e6..00000000000 --- a/packages/shared/lib/sdk/sync.ts +++ /dev/null @@ -1,1310 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unnecessary-type-parameters */ -import https from 'node:https'; -import { Nango, getUserAgent } from '@nangohq/node'; -import type { AdminAxiosProps } from '@nangohq/node'; -import paginateService from '../services/paginate.service.js'; -import proxyService from '../services/proxy.service.js'; -import type { AxiosInstance, AxiosInterceptorManager, AxiosRequestConfig, AxiosResponse } from 'axios'; -import axios, { AxiosError } from 'axios'; -import { getPersistAPIUrl } from '../utils/utils.js'; -import type { UserProvidedProxyConfiguration } from '../models/Proxy.js'; -import { - getLogger, - httpRetryStrategy, - metrics, - retryWithBackoff, - MAX_LOG_PAYLOAD, - stringifyAndTruncateValue, - stringifyObject, - truncateJson -} from '@nangohq/utils'; -import type { ValidateDataError } from './dataValidation.js'; -import { validateData } from './dataValidation.js'; -import { NangoError } from '../utils/error.js'; -import type { ApiEndUser, DBSyncConfig, DBTeam, GetPublicIntegration, MessageRowInsert, RunnerFlags } from '@nangohq/types'; -import { getProvider } from '../services/providers.js'; -import { redactHeaders, redactURL } from '../utils/http.js'; - -const logger = getLogger('SDK'); - -export const oldLevelToNewLevel = { - debug: 'debug', - info: 'info', - warn: 'warn', - error: 'error', - verbose: 'debug', - silly: 'debug', - http: 'info' -} as const; - -/* - * - * NOTICE!! - * This file is imported from the cli so any type needs to be explicitly - * specified in this file because imports won't resolve when copying - * over this file to the cli - * - */ - -type LogLevel = 'info' | 'debug' | 'error' | 'warn' | 'http' | 'verbose' | 'silly'; -const logLevelToLogger = { - info: 'info', - debug: 'debug', - error: 'error', - warn: 'warning', - http: 'info', - verbose: 'debug', - silly: 'debug' -} as const; - -type ParamEncoder = (value: any, defaultEncoder: (value: any) => any) => any; - -interface GenericFormData { - append(name: string, value: any, options?: any): any; -} - -type SerializerVisitor = ( - this: GenericFormData, - value: any, - key: string | number, - path: null | (string | number)[], - helpers: FormDataVisitorHelpers -) => boolean; - -type CustomParamsSerializer = (params: Record, options?: ParamsSerializerOptions) => string; - -interface FormDataVisitorHelpers { - defaultVisitor: SerializerVisitor; - convertValue: (value: any) => any; - isVisitable: (value: any) => boolean; -} - -interface SerializerOptions { - visitor?: SerializerVisitor; - dots?: boolean; - metaTokens?: boolean; - indexes?: boolean | null; -} - -interface ParamsSerializerOptions extends SerializerOptions { - encode?: ParamEncoder; - serialize?: CustomParamsSerializer; -} - -interface UserLogParameters { - level?: LogLevel; -} - -enum PaginationType { - CURSOR = 'cursor', - LINK = 'link', - OFFSET = 'offset' -} - -interface Pagination { - type: string; - limit?: number; - response_path?: string; - limit_name_in_request: string; -} - -interface CursorPagination extends Pagination { - cursor_path_in_response: string; - cursor_name_in_request: string; -} - -interface LinkPagination extends Pagination { - link_rel_in_response_header?: string; - link_path_in_response_body?: string; -} - -interface OffsetPagination extends Pagination { - offset_name_in_request: string; - offset_start_value?: number; - offset_calculation_method?: 'per-page' | 'by-response-size'; -} - -interface RetryHeaderConfig { - at?: string; - after?: string; -} - -export interface ProxyConfiguration { - endpoint: string; - providerConfigKey?: string; - connectionId?: string; - - method?: 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE' | 'get' | 'post' | 'patch' | 'put' | 'delete'; - headers?: Record; - params?: string | Record; - paramsSerializer?: ParamsSerializerOptions; - data?: unknown; - retries?: number; - baseUrlOverride?: string; - paginate?: Partial | Partial | Partial; - retryHeader?: RetryHeaderConfig; - responseType?: 'arraybuffer' | 'blob' | 'document' | 'json' | 'text' | 'stream'; - retryOn?: number[] | null; -} - -export interface AuthModes { - OAuth1: 'OAUTH1'; - OAuth2: 'OAUTH2'; - OAuth2CC: 'OAUTH2_CC'; - Basic: 'BASIC'; - ApiKey: 'API_KEY'; - AppStore: 'APP_STORE'; - Custom: 'CUSTOM'; - App: 'APP'; - None: 'NONE'; - TBA: 'TBA'; - Tableau: 'TABLEAU'; - Jwt: 'JWT'; - Bill: 'BILL'; - TwoStep: 'TWO_STEP'; - Signature: 'SIGNATURE'; -} -export type AuthModeType = AuthModes[keyof AuthModes]; - -interface OAuth1Token { - oAuthToken: string; - oAuthTokenSecret: string; -} - -interface AppCredentials { - type: AuthModes['App']; - access_token: string; - expires_at?: Date | undefined; - raw: Record; -} - -interface AppStoreCredentials { - type?: AuthModes['AppStore']; - access_token: string; - expires_at?: Date | undefined; - raw: Record; - private_key: string; -} - -interface BasicApiCredentials { - type: AuthModes['Basic']; - username: string; - password: string; -} - -interface ApiKeyCredentials { - type: AuthModes['ApiKey']; - apiKey: string; -} - -interface CredentialsCommon> { - type: AuthModeType; - raw: T; -} - -interface OAuth2Credentials extends CredentialsCommon { - type: AuthModes['OAuth2']; - access_token: string; - - refresh_token?: string; - expires_at?: Date | undefined; -} - -interface OAuth2ClientCredentials extends CredentialsCommon { - type: AuthModes['OAuth2CC']; - token: string; - - expires_at?: Date | undefined; - - client_id: string; - client_secret: string; -} - -interface OAuth1Credentials extends CredentialsCommon { - type: AuthModes['OAuth1']; - oauth_token: string; - oauth_token_secret: string; -} - -interface TbaCredentials { - type: AuthModes['TBA']; - token_id: string; - token_secret: string; - - config_override: { - client_id?: string; - client_secret?: string; - }; -} -interface TableauCredentials extends CredentialsCommon { - type: AuthModes['Tableau']; - pat_name: string; - pat_secret: string; - content_url?: string; - token?: string; - expires_at?: Date | undefined; -} -interface JwtCredentials { - type: AuthModes['Jwt']; - privateKeyId?: string; - issuerId?: string; - privateKey: - | { - id: string; - secret: string; - } - | string; // Colon-separated string for Ghost Admin: 'id:secret' - token?: string; - expires_at?: Date | undefined; -} -interface BillCredentials extends CredentialsCommon { - type: AuthModes['Bill']; - username: string; - password: string; - organization_id: string; - dev_key: string; - session_id?: string; - user_id?: string; - expires_at?: Date | undefined; -} -interface TwoStepCredentials extends CredentialsCommon { - type: AuthModes['TwoStep']; - [key: string]: any; - token?: string; - expires_at?: Date | undefined; -} -interface SignatureCredentials { - type: AuthModes['Signature']; - username: string; - password: string; - token?: string; - expires_at?: Date | undefined; -} -interface CustomCredentials extends CredentialsCommon { - type: AuthModes['Custom']; -} - -type UnauthCredentials = Record; - -type AuthCredentials = - | OAuth2Credentials - | OAuth2ClientCredentials - | OAuth1Credentials - | BasicApiCredentials - | ApiKeyCredentials - | AppCredentials - | AppStoreCredentials - | UnauthCredentials - | TbaCredentials - | TableauCredentials - | JwtCredentials - | BillCredentials - | TwoStepCredentials - | SignatureCredentials - | CustomCredentials; - -type Metadata = Record; - -interface MetadataChangeResponse { - metadata: Metadata; - provider_config_key: string; - connection_id: string | string[]; -} - -interface Connection { - id: number; - provider_config_key: string; - connection_id: string; - connection_config: Record; - created_at: string; - updated_at: string; - last_fetched_at: string; - metadata: Record | null; - provider: string; - errors: { type: string; log_id: string }[]; - end_user: ApiEndUser | null; - credentials: AuthCredentials; -} - -export class ActionError> extends Error { - type: string; - payload?: Record; - - constructor(payload?: T) { - super(); - this.type = 'action_script_runtime_error'; - if (payload) { - this.payload = payload; - } - } -} - -interface RunArgs { - sync: string; - connectionId: string; - lastSyncDate?: string; - useServerLastSyncDate?: boolean; - input?: object; - metadata?: Metadata; - autoConfirm: boolean; - debug: boolean; - optionalEnvironment?: string; - optionalProviderConfigKey?: string; -} - -export interface DryRunServiceInterface { - run: (options: RunArgs, debug?: boolean) => Promise; -} - -export interface NangoProps { - scriptType: 'sync' | 'action' | 'webhook' | 'on-event'; - host?: string; - secretKey: string; - team?: Pick; - connectionId: string; - environmentId: number; - environmentName?: string; - activityLogId?: string | undefined; - providerConfigKey: string; - provider: string; - lastSyncDate?: Date; - syncId?: string | undefined; - nangoConnectionId?: number; - syncJobId?: number | undefined; - dryRun?: boolean; - track_deletes?: boolean; - attributes?: object | undefined; - logMessages?: { counts: { updated: number; added: number; deleted: number }; messages: unknown[] } | undefined; - rawSaveOutput?: Map | undefined; - rawDeleteOutput?: Map | undefined; - stubbedMetadata?: Metadata | undefined; - abortSignal?: AbortSignal; - dryRunService?: DryRunServiceInterface; - syncConfig: DBSyncConfig; - runnerFlags: RunnerFlags; - debug: boolean; - startedAt: Date; - endUser: { id: number; endUserId: string | null; orgId: string | null } | null; - - axios?: { - request?: AxiosInterceptorManager; - response?: { - onFulfilled: (value: AxiosResponse) => AxiosResponse | Promise; - onRejected: (value: unknown) => AxiosError | Promise; - }; - }; -} - -export interface EnvironmentVariable { - name: string; - value: string; -} - -const MEMOIZED_CONNECTION_TTL = 60000; -const MEMOIZED_INTEGRATION_TTL = 10 * 60 * 1000; -const RECORDS_VALIDATION_SAMPLE = 5; - -export const defaultPersistApi = axios.create({ - baseURL: getPersistAPIUrl(), - httpsAgent: new https.Agent({ keepAlive: true }), - headers: { - 'User-Agent': getUserAgent('sdk') - }, - validateStatus: (_status) => { - return true; - } -}); - -export class NangoAction { - protected nango: Nango; - private attributes = {}; - protected persistApi: AxiosInstance; - activityLogId?: string | undefined; - syncId?: string; - nangoConnectionId?: number; - environmentId: number; - environmentName?: string; - syncJobId?: number; - dryRun?: boolean; - abortSignal?: AbortSignal; - dryRunService?: DryRunServiceInterface; - syncConfig?: DBSyncConfig; - runnerFlags: RunnerFlags; - - public connectionId: string; - public providerConfigKey: string; - public provider?: string; - - public ActionError = ActionError; - - private memoizedConnections = new Map(); - private memoizedIntegration = new Map(); - - constructor(config: NangoProps, { persistApi }: { persistApi: AxiosInstance } = { persistApi: defaultPersistApi }) { - this.connectionId = config.connectionId; - this.environmentId = config.environmentId; - this.providerConfigKey = config.providerConfigKey; - this.persistApi = persistApi; - this.runnerFlags = config.runnerFlags; - - if (config.activityLogId) { - this.activityLogId = config.activityLogId; - } - - const axiosSettings: AdminAxiosProps = { - userAgent: 'sdk' - }; - - if (config.syncId) { - this.syncId = config.syncId; - } - - if (config.nangoConnectionId) { - this.nangoConnectionId = config.nangoConnectionId; - } - - if (config.syncJobId) { - this.syncJobId = config.syncJobId; - } - - if (config.dryRun) { - this.dryRun = config.dryRun; - - if (config.axios?.response) { - axiosSettings.interceptors = { - response: { - onFulfilled: config.axios.response.onFulfilled, - onRejected: config.axios.response.onRejected - } - }; - } - } - if (!config.axios?.response) { - // Leave the priority to saving response instead of logging - axiosSettings.interceptors = { - response: { - onFulfilled: this.logAPICall.bind(this) - } - }; - } - - if (config.environmentName) { - this.environmentName = config.environmentName; - } - - if (config.provider) { - this.provider = config.provider; - } - - if (config.attributes) { - this.attributes = config.attributes; - } - - if (config.abortSignal) { - this.abortSignal = config.abortSignal; - } - - if (config.dryRunService) { - this.dryRunService = config.dryRunService; - } - - if (config.syncConfig) { - this.syncConfig = config.syncConfig; - } - - this.nango = new Nango({ isSync: true, ...config }, axiosSettings); - - if (this.dryRun !== true) { - if (!this.activityLogId) throw new Error('Parameter activityLogId is required when not in dryRun'); - if (!this.environmentId) throw new Error('Parameter environmentId is required when not in dryRun'); - if (!this.nangoConnectionId) throw new Error('Parameter nangoConnectionId is required when not in dryRun'); - if (!this.syncConfig) throw new Error('Parameter syncConfig is required when not in dryRun'); - } - } - - protected stringify(): string { - return JSON.stringify(this, (key, value) => { - if (key === 'secretKey') { - return '********'; - } - return value; - }); - } - - private proxyConfig(config: ProxyConfiguration): UserProvidedProxyConfiguration { - if (!config.connectionId && this.connectionId) { - config.connectionId = this.connectionId; - } - if (!config.providerConfigKey && this.providerConfigKey) { - config.providerConfigKey = this.providerConfigKey; - } - if (!config.connectionId) { - throw new Error('Missing connection id'); - } - if (!config.providerConfigKey) { - throw new Error('Missing provider config key'); - } - return { - method: 'GET', - ...config, - providerConfigKey: config.providerConfigKey, - connectionId: config.connectionId, - headers: { - ...(config.headers || {}), - 'user-agent': this.nango.userAgent - } - }; - } - - protected throwIfAborted(): void { - if (this.abortSignal?.aborted) { - throw new NangoError('script_aborted'); - } - } - - public async proxy(config: ProxyConfiguration): Promise> { - this.throwIfAborted(); - if (!config.method) { - config.method = 'GET'; - } - - if (this.dryRun) { - return this.nango.proxy(config); - } else { - const { connectionId, providerConfigKey } = config; - const connection = await this.getConnection(providerConfigKey, connectionId); - if (!connection) { - throw new Error(`Connection not found using the provider config key ${this.providerConfigKey} and connection id ${this.connectionId}`); - } - - const proxyConfig = this.proxyConfig(config); - - const { response, logs } = await proxyService.route(proxyConfig, { - existingActivityLogId: this.activityLogId as string, - connection, - providerName: this.provider as string - }); - - // We batch save, since we have buffered the createdAt it shouldn't impact order - await Promise.all( - logs.map(async (log) => { - if (log.level === 'debug') { - return; - } - await this.sendLogToPersist(log); - }) - ); - - if (response instanceof Error) { - throw response; - } - - return response; - } - } - - public async get(config: Omit): Promise> { - return this.proxy({ - ...config, - method: 'GET' - }); - } - - public async post(config: Omit): Promise> { - return this.proxy({ - ...config, - method: 'POST' - }); - } - - public async put(config: Omit): Promise> { - return this.proxy({ - ...config, - method: 'PUT' - }); - } - - public async patch(config: Omit): Promise> { - return this.proxy({ - ...config, - method: 'PATCH' - }); - } - - public async delete(config: Omit): Promise> { - return this.proxy({ - ...config, - method: 'DELETE' - }); - } - - public async getToken(): Promise< - | string - | OAuth1Token - | OAuth2ClientCredentials - | BasicApiCredentials - | ApiKeyCredentials - | AppCredentials - | AppStoreCredentials - | UnauthCredentials - | CustomCredentials - | TbaCredentials - | TableauCredentials - | JwtCredentials - | BillCredentials - | TwoStepCredentials - | SignatureCredentials - > { - this.throwIfAborted(); - return this.nango.getToken(this.providerConfigKey, this.connectionId); - } - - /** - * Get current integration - */ - public async getIntegration(queries?: GetPublicIntegration['Querystring']): Promise { - this.throwIfAborted(); - - const key = queries?.include?.join(',') || 'default'; - const has = this.memoizedIntegration.get(key); - if (has && MEMOIZED_INTEGRATION_TTL > Date.now() - has.timestamp) { - return has.integration; - } - - const { data: integration } = await this.nango.getIntegration({ uniqueKey: this.providerConfigKey }, queries); - this.memoizedIntegration.set(key, { integration, timestamp: Date.now() }); - return integration; - } - - public async getConnection(providerConfigKeyOverride?: string, connectionIdOverride?: string): Promise { - this.throwIfAborted(); - - const providerConfigKey = providerConfigKeyOverride || this.providerConfigKey; - const connectionId = connectionIdOverride || this.connectionId; - - const credentialsPair = `${providerConfigKey}${connectionId}`; - const cachedConnection = this.memoizedConnections.get(credentialsPair); - - if (!cachedConnection || Date.now() - cachedConnection.timestamp > MEMOIZED_CONNECTION_TTL) { - const connection = await this.nango.getConnection(providerConfigKey, connectionId); - this.memoizedConnections.set(credentialsPair, { connection, timestamp: Date.now() }); - return connection; - } - - return cachedConnection.connection; - } - - public async setMetadata(metadata: Metadata): Promise> { - this.throwIfAborted(); - try { - return await this.nango.setMetadata(this.providerConfigKey, this.connectionId, metadata); - } finally { - this.memoizedConnections.delete(`${this.providerConfigKey}${this.connectionId}`); - } - } - - public async updateMetadata(metadata: Metadata): Promise> { - this.throwIfAborted(); - try { - return await this.nango.updateMetadata(this.providerConfigKey, this.connectionId, metadata); - } finally { - this.memoizedConnections.delete(`${this.providerConfigKey}${this.connectionId}`); - } - } - - /** - * @deprecated please use setMetadata instead. - */ - public async setFieldMapping(fieldMapping: Record): Promise> { - logger.warning('setFieldMapping is deprecated. Please use setMetadata instead.'); - return this.setMetadata(fieldMapping); - } - - public async getMetadata(): Promise { - this.throwIfAborted(); - return (await this.getConnection(this.providerConfigKey, this.connectionId)).metadata as T; - } - - public async getWebhookURL(): Promise { - this.throwIfAborted(); - const integration = await this.getIntegration({ include: ['webhook'] }); - return integration.webhook_url; - } - - /** - * @deprecated please use getMetadata instead. - */ - public async getFieldMapping(): Promise { - logger.warning('getFieldMapping is deprecated. Please use getMetadata instead.'); - const metadata = await this.getMetadata(); - return (metadata['fieldMapping'] as Metadata) || {}; - } - - /** - * Log - * @desc Log a message to the activity log which shows up in the Nango Dashboard - * note that the last argument can be an object with a level property to specify the log level - * @example - * ```ts - * await nango.log('This is a log message', { level: 'error' }) - * ``` - */ - public async log(message: any, options?: { level?: LogLevel } | { [key: string]: any; level?: never }): Promise; - public async log(message: string, ...args: [any, { level?: LogLevel }]): Promise; - public async log(...args: [...any]): Promise { - this.throwIfAborted(); - if (args.length === 0) { - return; - } - - const lastArg = args[args.length - 1]; - - const isUserDefinedLevel = (object: UserLogParameters): boolean => { - return lastArg && typeof lastArg === 'object' && 'level' in object; - }; - - const userDefinedLevel: UserLogParameters | undefined = isUserDefinedLevel(lastArg) ? lastArg : undefined; - - if (userDefinedLevel) { - args.pop(); - } - - const level = userDefinedLevel?.level ?? 'info'; - - if (this.dryRun) { - const logLevel = logLevelToLogger[level] ?? 'info'; - - // TODO: we shouldn't use a floating logger, it should be passed from dryrun or runner - if (args.length > 1 && 'type' in args[1] && args[1].type === 'http') { - logger[logLevel].apply(null, [args[0], { status: args[1]?.response?.code || 'xxx' }] as any); - } else { - logger[logLevel].apply(null, args as any); - } - - return; - } - - const [message, payload] = args; - - // arrays are not supported in the log meta, so we convert them to objects - const meta = Array.isArray(payload) ? Object.fromEntries(payload.map((e, i) => [i, e])) : payload || null; - - await this.sendLogToPersist({ - type: 'log', - level: oldLevelToNewLevel[level], - source: 'user', - message: stringifyAndTruncateValue(message), - meta, - createdAt: new Date().toISOString(), - environmentId: this.environmentId - }); - } - - public async getEnvironmentVariables(): Promise { - return await this.nango.getEnvironmentVariables(); - } - - public getFlowAttributes(): A | null { - if (!this.syncJobId) { - throw new Error('There is no current sync to get attributes from'); - } - - return this.attributes as A; - } - - public async *paginate(config: ProxyConfiguration): AsyncGenerator { - const provider = getProvider(this.provider as string); - if (!provider) { - throw new NangoError('unknown_provider_template_in_config'); - } - - const templatePaginationConfig = provider.proxy?.paginate; - - if (!templatePaginationConfig && (!config.paginate || !config.paginate.type)) { - throw Error('There was no pagination configuration for this integration or configuration passed in.'); - } - - const paginationConfig = { - ...(templatePaginationConfig || {}), - ...(config.paginate || {}) - } as Pagination; - - paginateService.validateConfiguration(paginationConfig); - - config.method = config.method || 'GET'; - - const configMethod = config.method.toLocaleLowerCase(); - const passPaginationParamsInBody: boolean = ['post', 'put', 'patch'].includes(configMethod); - - const updatedBodyOrParams: Record = ((passPaginationParamsInBody ? config.data : config.params) as Record) ?? {}; - const limitParameterName: string = paginationConfig.limit_name_in_request; - - if (paginationConfig['limit']) { - updatedBodyOrParams[limitParameterName] = paginationConfig['limit']; - } - - const proxyConfig = this.proxyConfig(config); - switch (paginationConfig.type.toLowerCase()) { - case PaginationType.CURSOR: - return yield* paginateService.cursor( - proxyConfig, - paginationConfig as CursorPagination, - updatedBodyOrParams, - passPaginationParamsInBody, - this.proxy.bind(this) - ); - case PaginationType.LINK: - return yield* paginateService.link(proxyConfig, paginationConfig, updatedBodyOrParams, passPaginationParamsInBody, this.proxy.bind(this)); - case PaginationType.OFFSET: - return yield* paginateService.offset( - proxyConfig, - paginationConfig as OffsetPagination, - updatedBodyOrParams, - passPaginationParamsInBody, - this.proxy.bind(this) - ); - default: - throw Error( - `'${paginationConfig.type} ' pagination is not supported. Please, make sure it's one of ${Object.values(PaginationType).join(', ')}` - ); - } - } - - public async triggerAction(providerConfigKey: string, connectionId: string, actionName: string, input?: In): Promise { - return await this.nango.triggerAction(providerConfigKey, connectionId, actionName, input); - } - - public async triggerSync(providerConfigKey: string, connectionId: string, syncName: string, fullResync?: boolean): Promise { - if (this.dryRun && this.dryRunService) { - return this.dryRunService.run({ - sync: syncName, - connectionId, - autoConfirm: true, - debug: false - }); - } else { - return this.nango.triggerSync(providerConfigKey, [syncName], connectionId, fullResync); - } - } - - private async sendLogToPersist(log: MessageRowInsert) { - let response: AxiosResponse; - try { - response = await retryWithBackoff( - async () => { - let data = stringifyObject({ activityLogId: this.activityLogId, log }); - - // We try to keep log object under an acceptable size, before reaching network - // The idea is to always log something instead of silently crashing without overloading persist - if (data.length > MAX_LOG_PAYLOAD) { - log.message += ` ... (truncated, payload was too large)`; - // Truncating can remove mandatory field so we only try to truncate meta - if (log.meta) { - data = stringifyObject({ - activityLogId: this.activityLogId, - log: { ...log, meta: truncateJson(log.meta) as MessageRowInsert['meta'] } - }); - } - } - - return await this.persistApi({ - method: 'POST', - url: `/environment/${this.environmentId}/log`, - headers: { - Authorization: `Bearer ${this.nango.secretKey}`, - 'Content-Type': 'application/json' - }, - data - }); - }, - { retry: httpRetryStrategy } - ); - } catch (err) { - logger.error('Failed to log to persist, due to an internal error', err instanceof AxiosError ? err.code : err); - // We don't want to block a sync because logging failed, so we fail silently until we have a way to report error - // TODO: find a way to report that - return; - } - - if (response.status > 299) { - logger.error( - `Request to persist API (log) failed: errorCode=${response.status} response='${JSON.stringify(response.data)}' log=${JSON.stringify(log)}`, - this.stringify() - ); - throw new Error(`Failed to log: ${JSON.stringify(response.data)}`); - } - } - - private logAPICall(res: AxiosResponse): AxiosResponse { - if (!res.config.url) { - return res; - } - - // We compte on the fly because connection's credentials can change during a single run - // We could further optimize this and cache it when the memoizedConnection is updated - const valuesToFilter: string[] = [ - ...Array.from(this.memoizedConnections.values()).reduce((acc, conn) => { - if (!conn) { - return acc; - } - acc.push(...Object.values(conn.connection.credentials)); - return acc; - }, []), - this.nango.secretKey - ]; - - const method = res.config.method?.toLocaleUpperCase(); // axios put it in lowercase; - void this.log( - `${method} ${res.config.url}`, - { - type: 'http', - request: { - method: method, - url: redactURL({ url: res.config.url, valuesToFilter }), - headers: redactHeaders({ headers: res.config.headers, valuesToFilter }) - }, - response: { - code: res.status, - headers: redactHeaders({ headers: res.headers, valuesToFilter }) - } - }, - { level: res.status > 299 ? 'error' : 'info' } - ); - return res; - } -} - -export class NangoSync extends NangoAction { - lastSyncDate?: Date; - track_deletes = false; - logMessages?: { counts: { updated: number; added: number; deleted: number }; messages: unknown[] } | undefined = { - counts: { updated: 0, added: 0, deleted: 0 }, - messages: [] - }; - rawSaveOutput?: Map; - rawDeleteOutput?: Map; - stubbedMetadata?: Metadata | undefined = undefined; - - private batchSize = 1000; - - constructor(config: NangoProps) { - super(config); - - if (config.lastSyncDate) { - this.lastSyncDate = config.lastSyncDate; - } - - if (config.track_deletes) { - this.track_deletes = config.track_deletes; - } - - if (config.logMessages) { - this.logMessages = config.logMessages; - } - - if (config.rawSaveOutput) { - this.rawSaveOutput = config.rawSaveOutput; - } - - if (config.rawDeleteOutput) { - this.rawDeleteOutput = config.rawDeleteOutput; - } - - if (config.stubbedMetadata) { - this.stubbedMetadata = config.stubbedMetadata; - } - if (!config.dryRun) { - if (!this.syncId) throw new Error('Parameter syncId is required when not in dryRun'); - if (!this.syncJobId) throw new Error('Parameter syncJobId is required when not in dryRun'); - } - } - - /** - * @deprecated please use batchSave - */ - public async batchSend(results: T[], model: string): Promise { - logger.warning('batchSend will be deprecated in future versions. Please use batchSave instead.'); - return this.batchSave(results, model); - } - - public async batchSave(results: T[], model: string): Promise { - this.throwIfAborted(); - - if (!results || results.length === 0) { - if (this.dryRun) { - logger.info('batchSave received an empty array. No records to save.'); - } - return true; - } - - // Validate records - const hasErrors: { data: any; validation: ValidateDataError[] }[] = []; - for (const record of results) { - const validation = validateData({ - version: this.syncConfig?.version || '1', - input: JSON.parse(JSON.stringify(record)), - jsonSchema: this.syncConfig!.models_json_schema, - modelName: model - }); - if (validation === true) { - continue; - } - - hasErrors.push({ data: record, validation }); - metrics.increment(metrics.Types.RUNNER_INVALID_SYNCS_RECORDS); - - if (this.runnerFlags?.validateSyncRecords) { - break; - } - } - if (hasErrors.length > 0) { - if (this.dryRun) { - await this.log('Invalid record payload. Use `--validation` option to see the details', { level: 'warn' }); - } - if (this.runnerFlags?.validateSyncRecords) { - throw new NangoError(`invalid_sync_record`, { ...hasErrors[0], model }); - } - - const sampled = hasErrors.length > RECORDS_VALIDATION_SAMPLE; - const sample = sampled ? hasErrors.slice(0, RECORDS_VALIDATION_SAMPLE) : hasErrors; - if (sampled) { - await this.log(`Invalid records: ${hasErrors.length} failed ${sampled ? `(sampled to ${RECORDS_VALIDATION_SAMPLE})` : ''}`, { level: 'warn' }); - } - await Promise.all( - sample.map((log) => { - return this.log(`Invalid record payload`, { ...log, model }, { level: 'warn' }); - }) - ); - } - - if (this.dryRun) { - this.logMessages?.messages.push(`A batch save call would save the following data to the ${model} model:`); - for (const msg of results) { - this.logMessages?.messages.push(msg); - } - if (this.logMessages && this.logMessages.counts) { - this.logMessages.counts.added = Number(this.logMessages.counts.added) + results.length; - } - if (this.rawSaveOutput) { - if (!this.rawSaveOutput.has(model)) { - this.rawSaveOutput.set(model, []); - } - this.rawSaveOutput.get(model)?.push(...results); - } - return null; - } - - for (let i = 0; i < results.length; i += this.batchSize) { - const batch = results.slice(i, i + this.batchSize); - let response: AxiosResponse; - try { - response = await retryWithBackoff( - () => { - return this.persistApi({ - method: 'POST', - url: `/environment/${this.environmentId}/connection/${this.nangoConnectionId}/sync/${this.syncId}/job/${this.syncJobId}/records`, - headers: { - Authorization: `Bearer ${this.nango.secretKey}` - }, - data: { - model, - records: batch, - providerConfigKey: this.providerConfigKey, - connectionId: this.connectionId, - activityLogId: this.activityLogId - } - }); - }, - { retry: httpRetryStrategy } - ); - } catch (err) { - logger.error('Internal error', err instanceof AxiosError ? err.code : err); - throw new Error('Failed to save records due to an internal error', { cause: err }); - } - - if (response.status > 299) { - logger.error( - `Request to persist API (batchSave) failed: errorCode=${response.status} response='${JSON.stringify(response.data)}'`, - this.stringify() - ); - - if (response.status === 400) { - throw new Error( - `Records invalid format. Please make sure you are sending an array of objects that each contain an 'id' property with type string` - ); - } else { - const message = 'error' in response.data && 'message' in response.data.error ? response.data.error.message : JSON.stringify(response.data); - throw new Error(message); - } - } - } - return true; - } - - public async batchDelete(results: T[], model: string): Promise { - this.throwIfAborted(); - if (!results || results.length === 0) { - if (this.dryRun) { - logger.info('batchDelete received an empty array. No records to delete.'); - } - return true; - } - - if (this.dryRun) { - this.logMessages?.messages.push(`A batch delete call would delete the following data:`); - for (const msg of results) { - this.logMessages?.messages.push(msg); - } - if (this.logMessages && this.logMessages.counts) { - this.logMessages.counts.deleted = Number(this.logMessages.counts.deleted) + results.length; - } - if (this.rawDeleteOutput) { - if (!this.rawDeleteOutput.has(model)) { - this.rawDeleteOutput.set(model, []); - } - this.rawDeleteOutput.get(model)?.push(...results); - } - return null; - } - - for (let i = 0; i < results.length; i += this.batchSize) { - const batch = results.slice(i, i + this.batchSize); - let response: AxiosResponse; - try { - response = await retryWithBackoff( - async () => { - return await this.persistApi({ - method: 'DELETE', - url: `/environment/${this.environmentId}/connection/${this.nangoConnectionId}/sync/${this.syncId}/job/${this.syncJobId}/records`, - headers: { - Authorization: `Bearer ${this.nango.secretKey}` - }, - data: { - model, - records: batch, - providerConfigKey: this.providerConfigKey, - connectionId: this.connectionId, - activityLogId: this.activityLogId - } - }); - }, - { retry: httpRetryStrategy } - ); - } catch (err) { - logger.error('Internal error', err instanceof AxiosError ? err.code : err); - throw new Error('Failed to delete records due to an internal error', { cause: err }); - } - - if (response.status > 299) { - logger.error( - `Request to persist API (batchDelete) failed: errorCode=${response.status} response='${JSON.stringify(response.data)}'`, - this.stringify() - ); - const message = 'error' in response.data && 'message' in response.data.error ? response.data.error.message : JSON.stringify(response.data); - throw new Error(message); - } - } - return true; - } - - public async batchUpdate(results: T[], model: string): Promise { - this.throwIfAborted(); - if (!results || results.length === 0) { - if (this.dryRun) { - logger.info('batchUpdate received an empty array. No records to update.'); - } - return true; - } - - if (this.dryRun) { - this.logMessages?.messages.push(`A batch update call would update the following data to the ${model} model:`); - for (const msg of results) { - this.logMessages?.messages.push(msg); - } - if (this.logMessages && this.logMessages.counts) { - this.logMessages.counts.updated = Number(this.logMessages.counts.updated) + results.length; - } - return null; - } - - for (let i = 0; i < results.length; i += this.batchSize) { - const batch = results.slice(i, i + this.batchSize); - let response: AxiosResponse; - try { - response = await retryWithBackoff( - async () => { - return await this.persistApi({ - method: 'PUT', - url: `/environment/${this.environmentId}/connection/${this.nangoConnectionId}/sync/${this.syncId}/job/${this.syncJobId}/records`, - headers: { - Authorization: `Bearer ${this.nango.secretKey}` - }, - data: { - model, - records: batch, - providerConfigKey: this.providerConfigKey, - connectionId: this.connectionId, - activityLogId: this.activityLogId - } - }); - }, - { retry: httpRetryStrategy } - ); - } catch (err) { - logger.error('Internal error', err instanceof AxiosError ? err.code : err); - throw new Error('Failed to update records due to an internal error', { cause: err }); - } - - if (response.status > 299) { - logger.error( - `Request to persist API (batchUpdate) failed: errorCode=${response.status} response='${JSON.stringify(response.data)}'`, - this.stringify() - ); - const message = 'error' in response.data && 'message' in response.data.error ? response.data.error.message : JSON.stringify(response.data); - throw new Error(message); - } - } - return true; - } - - public override async getMetadata(): Promise { - this.throwIfAborted(); - if (this.dryRun && this.stubbedMetadata) { - return this.stubbedMetadata as T; - } - - return super.getMetadata(); - } -} - -const TELEMETRY_ALLOWED_METHODS: (keyof NangoSync)[] = [ - 'batchDelete', - 'batchSave', - 'batchSend', - 'getConnection', - 'getEnvironmentVariables', - 'getMetadata', - 'proxy', - 'log', - 'triggerAction', - 'triggerSync' -]; - -/** - * @internal - * - * This function will enable tracing on the SDK - * It has been split from the actual code to avoid making the code too dirty and to easily enable/disable tracing if there is an issue with it - */ -export function instrumentSDK(rawNango: NangoAction | NangoSync) { - return new Proxy(rawNango, { - get(target: T, propKey: K) { - // Method name is not matching the allowList we don't do anything else - if (!TELEMETRY_ALLOWED_METHODS.includes(propKey)) { - return target[propKey]; - } - - return metrics.time(`${metrics.Types.RUNNER_SDK}.${propKey}` as any, (target[propKey] as any).bind(target)); - } - }); -} diff --git a/packages/shared/lib/services/providers.ts b/packages/shared/lib/services/providers.ts index bce2b532a56..7ee64fc5398 100644 --- a/packages/shared/lib/services/providers.ts +++ b/packages/shared/lib/services/providers.ts @@ -1,31 +1,16 @@ -import path from 'node:path'; -import fs from 'node:fs'; -import yaml from 'js-yaml'; -import type { Provider, ProviderAlias } from '@nangohq/types'; +import type { Provider } from '@nangohq/types'; import { NangoError } from '../utils/error.js'; -import { dirname } from '../utils/utils.js'; import { getLogger, ENVS, parseEnvs } from '@nangohq/utils'; import { createHash } from 'node:crypto'; import { setTimeout } from 'node:timers/promises'; +import { updateProviderCache } from '@nangohq/providers'; + +// Just to avoid changing hundreds of refs +export { getProviders, getProvider } from '@nangohq/providers'; const logger = getLogger('providers'); const envs = parseEnvs(ENVS); -let providers: Record | undefined = undefined; - -export function getProviders() { - if (!providers) { - providers = loadProvidersYaml(); - } - - return providers; -} - -export function getProvider(providerName: string): Provider | null { - const providers = getProviders(); - return providers?.[providerName] ?? null; -} - let polling = false; let providersHash = ''; @@ -42,7 +27,7 @@ export async function monitorProviders(): Promise<() => void> { const providersRaw = await fetchProvidersRaw(providersUrl); providersHash = createHash('sha1').update(providersRaw).digest('hex'); - providers = JSON.parse(providersRaw) as Record; + updateProviderCache(JSON.parse(providersRaw) as Record); logger.info(`Providers loaded from url ${providersUrl} (${providersHash})`); void pollProviders(providersUrl); @@ -70,7 +55,7 @@ async function pollProviders(providersUrl: string) { if (newProvidersHash !== providersHash) { providersHash = newProvidersHash; - providers = JSON.parse(providersRaw) as Record; + updateProviderCache(JSON.parse(providersRaw) as Record); logger.info(`Providers reloaded (${providersHash})`); } } catch (err) { @@ -88,50 +73,3 @@ async function fetchProvidersRaw(providersUrl: string): Promise { return await response.text(); } - -function getProvidersPath() { - // find the providers.yaml file - // recursively searching in parent directories - const findProvidersYaml = (dir: string): string => { - const providersYamlPath = path.join(dir, 'providers.yaml'); - if (fs.existsSync(providersYamlPath)) { - return providersYamlPath; - } - const parentDir = path.dirname(dir); - if (parentDir === dir) { - throw new NangoError('providers_yaml_not_found'); - } - return findProvidersYaml(parentDir); - }; - return findProvidersYaml(dirname()); -} - -function loadProvidersYaml(): Record | undefined { - try { - const fileEntries = yaml.load(fs.readFileSync(getProvidersPath()).toString()) as Record; - - if (fileEntries == null) { - throw new NangoError('provider_template_loading_failed'); - } - - for (const key in fileEntries) { - const entry = fileEntries[key]; - - if (entry && 'alias' in entry) { - if (Object.keys(entry).length <= 0) { - logger.error('Failed to find alias', entry.alias); - continue; - } - - const { alias, ...overrides } = entry; - const aliasData = fileEntries[entry.alias] as Provider; - fileEntries[key] = { ...aliasData, ...overrides }; - } - } - - return fileEntries as Record; - } catch (err) { - logger.error('Failed to load providers.yaml', err); - } - return; -} diff --git a/packages/shared/package.json b/packages/shared/package.json index b247e586036..70411819817 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -22,8 +22,8 @@ "@datadog/datadog-api-client": "1.26.0", "@hapi/boom": "^10.0.1", "@nangohq/database": "file:../database", - "@nangohq/nango-yaml": "0.48.3", - "@nangohq/node": "^0.48.3", + "@nangohq/nango-yaml": "file:../nango-yaml", + "@nangohq/providers": "file:../providers", "@nangohq/utils": "file:../utils", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", @@ -54,7 +54,7 @@ "devDependencies": { "@nangohq/logs": "file:../logs", "@nangohq/nango-orchestrator": "file:../orchestrator", - "@nangohq/types": "0.48.3", + "@nangohq/types": "file:../types", "@types/braintree": "^3.3.12", "@types/js-yaml": "^4.0.5", "@types/json-schema": "7.0.15", @@ -71,7 +71,6 @@ }, "files": [ "dist/**/*", - "flows.yaml", - "providers.yaml" + "flows.yaml" ] } diff --git a/packages/shared/providers.yaml b/packages/shared/providers.yaml deleted file mode 100644 index 415c2ed56a5..00000000000 --- a/packages/shared/providers.yaml +++ /dev/null @@ -1,7939 +0,0 @@ -# yaml-language-server: $schema=./../../scripts/validation/providers/schema.json -accelo: - display_name: Accelo - categories: - - invoicing - - ticketing - auth_mode: OAUTH2 - authorization_url: https://${connectionConfig.subdomain}.api.accelo.com/oauth2/v0/authorize - token_url: https://${connectionConfig.subdomain}.api.accelo.com/oauth2/v0/token - scope_separator: ',' - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://${connectionConfig.subdomain}.api.accelo.com - docs: https://docs.nango.dev/integrations/all/accelo - connection_config: - subdomain: - type: string - title: Accelo Domain - description: The subdomain of your Accelo account - pattern: '^[a-z0-9_-]+$' - example: domain - suffix: .api.accelo.com - prefix: https:// - -acuity-scheduling: - display_name: Acuity Scheduling - categories: - - productivity - auth_mode: OAUTH2 - authorization_url: https://acuityscheduling.com/oauth2/authorize - token_url: https://acuityscheduling.com/oauth2/token - default_scopes: - - api-v1 - proxy: - base_url: https://acuityscheduling.com/api/v1 - docs: https://docs.nango.dev/integrations/all/acuity-scheduling - -adobe: - display_name: Adobe - categories: - - design - auth_mode: OAUTH2 - authorization_url: https://ims-na1.adobelogin.com/ims/authorize/v2 - token_url: https://ims-na1.adobelogin.com/ims/token/v3 - default_scopes: - - offline_access - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://ims-na1.adobelogin.com/ims - docs: https://docs.nango.dev/integrations/all/adobe - -adobe-umapi: - display_name: UMAPI (Adobe User Management API) - categories: - - other - auth_mode: OAUTH2_CC - token_url: https://ims-na1.adobelogin.com/ims/token/v2 - scope_separator: ',' - token_params: - grant_type: client_credentials - proxy: - headers: - x-api-key: ${connectionConfig.clientId} - retry: - after: 'retry-after' - base_url: https://usermanagement.adobe.io - docs: https://docs.nango.dev/integrations/all/adobe - post_connection_script: adobeUmapiPostConnection - docs_connect: https://docs.nango.dev/integrations/all/adobe-umapi/connect - connection_config: - clientId: - type: string - title: '' - description: '' - automated: true - -adyen: - display_name: Adyen - categories: - - payment - auth_mode: OAUTH2 - authorization_url: https://ca-${connectionConfig.environment}.adyen.com/ca/ca/oauth/connect.shtml - token_url: https://oauth-${connectionConfig.environment}.adyen.com/v1/token - scope_separator: ' ' - token_request_auth_method: basic - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://${connectionConfig.resource}-${connectionConfig.environment}.adyen.com - docs: https://docs.nango.dev/integrations/all/adyen - connection_config: - environment: - type: string - title: Environment - description: The environment to use - pattern: '^(live|test)$' - example: live|test - resource: - type: string - title: Resource - description: The resource to use for your various requests - pattern: '^[a-z0-9_-]+$' - example: kyc - suffix: -(live|test).adyen.com - prefix: https:// - -affinity: - display_name: Affinity - categories: - - crm - auth_mode: BASIC - proxy: - base_url: https://api.affinity.co - verification: - method: GET - endpoint: /lists - docs: https://docs.nango.dev/integrations/all/affinity - docs_connect: https://docs.nango.dev/integrations/all/affinity/connect - credentials: - username: - type: string - title: '' - description: '' - default_value: '' - hidden: true - password: - type: string - title: API Key - description: Your Affinity API Key - # https://api-docs.affinity.co/#introduction - # Affinity is using basic auth with an api key - doc_section: '#step-1-finding-your-api-key' - -aircall: - display_name: Aircall - categories: - - support - auth_mode: OAUTH2 - authorization_url: https://dashboard.aircall.io/oauth/authorize - token_url: https://api.aircall.io/v1/oauth/token - authorization_params: - response_type: code - scope: public_api - token_params: - grant_type: authorization_code - proxy: - base_url: https://api.aircall.io - retry: - at: 'x-aircallapi-reset' - paginate: - type: link - link_path_in_response_body: meta.next_page_link - response_path: results - docs: https://docs.nango.dev/integrations/all/aircall - -aircall-basic: - alias: aircall - display_name: Aircall (basic auth) - auth_mode: BASIC - proxy: - base_url: https://api.aircall.io - verification: - method: GET - endpoint: /v1/ping - paginate: - type: link - link_path_in_response_body: meta.next_page_link - response_path: results - docs_connect: https://docs.nango.dev/integrations/all/aircall-basic/connect - docs: https://docs.nango.dev/integrations/all/aircall - -airtable: - display_name: Airtable - categories: - - productivity - auth_mode: OAUTH2 - authorization_url: https://airtable.com/oauth2/v1/authorize - token_url: https://airtable.com/oauth2/v1/token - authorization_method: header - auth: - response_type: code - proxy: - base_url: https://api.airtable.com - webhook_routing_script: airtableWebhookRouting - docs: https://docs.nango.dev/integrations/all/airtable - -autodesk: - display_name: Autodesk - categories: - - design - auth_mode: OAUTH2 - authorization_url: https://developer.api.autodesk.com/authentication/v2/authorize - token_url: https://developer.api.autodesk.com/authentication/v2/token - scope_separator: ' ' - disable_pkce: true - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://developer.api.autodesk.com - retry: - after: 'retry-after' - docs: https://docs.nango.dev/integrations/all/autodesk - -algolia: - display_name: Algolia - categories: - - search - auth_mode: API_KEY - proxy: - base_url: https://${connectionConfig.APP_ID}.algolia.net - headers: - x-algolia-application-id: ${connectionConfig.APP_ID} - x-algolia-api-key: ${apiKey} - verification: - endpoint: /1/keys/${credentials.apiKey} - docs: https://docs.nango.dev/integrations/all/algolia - docs_connect: https://docs.nango.dev/integrations/all/algolia/connect - connection_config: - APP_ID: - type: string - title: Application ID - description: The application ID for your Algolia account - example: ERBSOWZO32 - pattern: '^[A-Z0-9]{10}$' - order: 1 - doc_section: '#step-1-finding-your-application-id' - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Algolia account - example: c5c28261f9ade4e34891ccf761491b94 - pattern: '^[a-zA-Z0-9]+$' - doc_section: '#step-2-finding-your-admin-api-key' - -amazon: - display_name: Amazon - categories: - - dev-tools - - e-commerce - auth_mode: OAUTH2 - authorization_url: https://www.amazon.com/ap/oa - token_url: https://api.amazon.${connectionConfig.extension}/auth/o2/token - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://api.amazon.com - docs: https://docs.nango.dev/integrations/all/amazon - connection_config: - extension: - type: string - title: Domain Extension - description: The domain extension for your Amazon account - example: com - pattern: '^[a-z.]+$' - -anrok: - display_name: Anrok - categories: - - legal - auth_mode: API_KEY - proxy: - base_url: https://api.anrok.com - headers: - authorization: Bearer ${apiKey} - retry: - after: 'retry-after' - docs: https://docs.nango.dev/integrations/all/anrok - docs_connect: https://docs.nango.dev/integrations/all/anrok/connect - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Anrok account - doc_section: '#step-1-finding-your-api-key' - -amplitude: - display_name: Amplitude (Event Streaming API) - categories: - - analytics - auth_mode: BASIC - proxy: - base_url: https://amplitude.com - verification: - method: GET - endpoint: /api/2/events/list - docs: https://docs.nango.dev/integrations/all/amplitude - credentials: - username: - type: string - title: API Key - description: Your Amplitude API Key - password: - type: string - title: Secret Key - description: Your Amplitude secret key - # https://amplitude.com/docs/apis/authentication - # Amplitude is using basic auth with an api key - -anthropic: - display_name: Anthropic - categories: - - productivity - - dev-tools - auth_mode: API_KEY - proxy: - base_url: https://api.anthropic.com - headers: - x-api-key: ${apiKey} - anthropic-version: ${connectionConfig.version} - content-type: application/json - retry: - after: 'retry-after' - docs: https://docs.nango.dev/integrations/all/anthropic - connection_config: - version: - type: string - title: API Version - description: The version of the Anthropic API to use - pattern: '^[0-9]{4}-[0-9]{2}-[0-9]{2}$' - example: '2023-06-01' - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Anthropic account - -apaleo: - display_name: Apaleo - categories: - - erp - auth_mode: OAUTH2 - authorization_url: https://identity.apaleo.com/connect/authorize - token_url: https://identity.apaleo.com/connect/token - scope_separator: ' ' - token_params: - grant_type: authorization_code - authorization_params: - response_type: code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://api.apaleo.com - headers: - content-type: application/json - retry: - after: 'retry-after' - docs: https://docs.nango.dev/integrations/all/apaleo - -apollo: - display_name: Apollo - categories: - - marketing - auth_mode: API_KEY - proxy: - base_url: https://app.apollo.io/api - verification: - method: GET - endpoint: /v1/contact_stages - query: - api_key: ${apiKey} - docs: https://docs.nango.dev/integrations/all/apollo - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Apollo account - -apollo-oauth: - display_name: Apollo (OAuth) - categories: - - marketing - auth_mode: OAUTH2 - authorization_url: https://app.apollo.io - token_url: https://app.apollo.io/api/v1/oauth/token - authorization_url_fragment: oauth/authorize - body_format: json - disable_pkce: true - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://app.apollo.io/api - docs: https://docs.nango.dev/integrations/all/apollo - -apple-app-store: - display_name: Apple App Store - auth_mode: APP_STORE - token_url: https://api.appstoreconnect.apple.com/v1/apps - authorization_params: - audience: appstoreconnect-v1 - proxy: - base_url: https://api.appstoreconnect.apple.com - docs: https://docs.nango.dev/integrations/all/apple-app-store - -asana: - display_name: Asana - categories: - - productivity - - ticketing - auth_mode: OAUTH2 - authorization_url: https://app.asana.com/-/oauth_authorize - token_url: https://app.asana.com/-/oauth_token - token_params: - grant_type: authorization_code - auth: - response_type: code - default_scopes: - - default - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://app.asana.com - retry: - after: 'retry-after' - paginate: - type: cursor - cursor_path_in_response: next_page.offset - cursor_name_in_request: offset - response_path: data - limit_name_in_request: limit - docs: https://docs.nango.dev/integrations/all/asana - -asana-scim: - display_name: Asana (SCIM API) - categories: - - productivity - - ticketing - auth_mode: API_KEY - proxy: - base_url: https://app.asana.com/api - verification: - method: GET - endpoint: /1.0/scim/Users - headers: - authorization: Bearer ${apiKey} - docs: https://docs.nango.dev/integrations/all/asana - docs_connect: https://docs.nango.dev/integrations/all/asana-scim/connect - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Asana scim account - doc_section: '#step-1-finding-asana-api-key' - -ashby: - display_name: Ashby - categories: - - ats - auth_mode: BASIC - proxy: - base_url: https://api.ashbyhq.com - verification: - method: POST - endpoint: apiKey.info - docs: https://docs.nango.dev/integrations/all/ashby - credentials: - username: - type: string - title: API Key - description: The API Key of your Ashby account - password: - type: string - title: '' - description: '' - default_value: '' - hidden: true - -atlas-so: - display_name: Atlas.so - categories: - - support - auth_mode: API_KEY - proxy: - headers: - authorization: Bearer ${apiKey} - base_url: https://api.atlas.so/v1 - docs: https://docs.nango.dev/integrations/all/atlas-so - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Atlas.so account - -atlassian: - display_name: Atlassian - categories: - - dev-tools - auth_mode: OAUTH2 - authorization_url: https://auth.atlassian.com/authorize - token_url: https://auth.atlassian.com/oauth/token - default_scopes: - - offline_access - authorization_params: - response_type: code - audience: api.atlassian.com - prompt: consent - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://api.atlassian.com - docs: https://docs.nango.dev/integrations/all/atlassian - -attio: - display_name: Attio - categories: - - crm - auth_mode: OAUTH2 - authorization_url: https://app.attio.com/authorize - token_url: https://app.attio.com/oauth/token - token_params: - grant_type: authorization_code - auth: - response_type: code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://app.attio.com - docs: https://docs.nango.dev/integrations/all/attio - -auth0: - display_name: Auth0 - auth_mode: OAUTH2 - authorization_url: https://${connectionConfig.subdomain}.auth0.com/authorize - token_url: https://${connectionConfig.subdomain}.auth0.com/oauth/token - authorization_params: - response_type: code - response_mode: query - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - docs: https://docs.nango.dev/integrations/all/auth0 - proxy: - base_url: https://${connectionConfig.subdomain}.auth0.com - connection_config: - subdomain: - type: string - title: Auth0 Domain - description: The subdomain of your Auth0 account - pattern: '^[a-z0-9_-]+$' - example: domain - suffix: .auth0.com - prefix: https:// - -avalara: - display_name: Avalara - categories: - - legal - auth_mode: BASIC - proxy: - headers: - x-avalara-client: ${connectionConfig.avalaraClient} - content-type: application/json - base_url: https://rest.avatax.com/api/v2 - verification: - method: GET - endpoint: /utilities/subscriptions - docs: https://docs.nango.dev/integrations/all/avalara - docs_connect: https://docs.nango.dev/integrations/all/avalara/connect - credentials: - username: - type: string - title: User Name / Account ID - description: Avalara User Name / Account ID - doc_section: '#step-1-finding-your-pair-keys' - password: - type: string - title: Avalara Password / License Key - description: Your Password / License Key - # https://developer.avalara.com/avatax/authentication-in-rest/ - # Avalara is using basic auth with combination of (username and password) - # or (Account ID and License Key) - doc_section: '#step-1-finding-your-pair-keys' - connection_config: - avalaraClient: - type: string - title: Avalara Client - description: The Avalara client for your Avalara account - pattern: '^[a-zA-Z0-9_-]+$' - doc_section: '#step-2-generating-an-avalara-client' - -avalara-sandbox: - display_name: Avalara (sandbox) - categories: - - legal - auth_mode: BASIC - proxy: - headers: - x-avalara-client: ${connectionConfig.avalaraClient} - content-type: application/json - base_url: https://sandbox-rest.avatax.com/api/v2 - verification: - method: GET - endpoint: /utilities/subscriptions - docs: https://docs.nango.dev/integrations/all/avalara - docs_connect: https://docs.nango.dev/integrations/all/avalara-sandbox/connect - credentials: - username: - type: string - title: User Name / Account ID - description: Avalara User Name / Account ID - doc_section: '#step-1-finding-your-pair-keys' - password: - type: string - title: Password / License Key - description: Avalara Password / License Key - # https://developer.avalara.com/avatax/authentication-in-rest/ - # Avalara is using basic auth with combination of (username and password) - # or (Account ID and License Key) - doc_section: '#step-1-finding-your-pair-keys' - connection_config: - avalaraClient: - type: string - title: Avalara Client - description: The Avalara client for your Avalara account - pattern: '^[a-zA-Z0-9_-]+$' - doc_section: '#step-2-generating-an-avalara-client' - -aws: - display_name: AWS - categories: - - dev-tools - - e-commerce - auth_mode: OAUTH2 - authorization_url: https://${connectionConfig.subdomain}.auth.${connectionConfig.extension}.amazoncognito.com/oauth2/authorize - token_url: https://${connectionConfig.subdomain}.auth.${connectionConfig.extension}.amazoncognito.com/oauth2/token - token_params: - grant_type: authorization_code - auth: - response_type: code - refresh_params: - grant_type: refresh_token - default_scopes: - - openid - proxy: - base_url: https://cognito-${apiSubdomain}.amazonaws.com - docs: https://docs.nango.dev/integrations/all/aws - connection_config: - subdomain: - type: string - title: AWS Domain - description: The subdomain of your AWS account - pattern: '^[a-z0-9_-]+$' - example: domain - suffix: .amazoncognito.com - prefix: https:// - extension: - type: string - title: Domain Extension - description: The domain extension of your AWS account - example: com - pattern: '^[a-z.]+$' - apiSubdomain: - type: string - title: API Subdomain - description: The API subdomain to the API you want to connect to - example: idp.us-east-2 - pattern: '^[a-z.-]+$' - suffix: .amazonaws.com - prefix: https://cognito- - -aws-iam: - display_name: AWS IAM - categories: - - dev-tools - auth_mode: BASIC - proxy: - base_url: https://iam.amazonaws.com - verification: - method: GET - endpoint: /?Action=ListUsers - connection_config: - region: ${connectionConfig.region} - retry: - at: 'x-ratelimit-reset' - docs: https://docs.nango.dev/integrations/all/aws - docs_connect: https://docs.nango.dev/integrations/all/aws-iam/connect - credentials: - username: - type: string - title: AWS Access Key ID - description: Your Access Key ID - doc_section: '#step-1-finding-your-pair-keys' - password: - type: string - title: AWS Secret Access Key - description: Your Secret Access Key - # https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_sigv.html - # aws-iam is using basic auth with AWS Access Key ID and Secret Access Key - doc_section: '#step-1-finding-your-pair-keys' - connection_config: - region: - type: string - title: Region - description: The region to where your AWS account is hosted - example: us-east-1 - pattern: '^[a-z0-9-]+$' - doc_section: '#step-2-finding-your-region-host' - -bamboohr: - display_name: BambooHR - categories: - - hr - auth_mode: OAUTH2 - authorization_url: https://${connectionConfig.subdomain}.bamboohr.com/authorize.php - token_url: https://${connectionConfig.subdomain}.bamboohr.com/token.php - authorization_params: - response_type: code - request: authorize - token_params: - grant_type: authorization_code - request: token - proxy: - base_url: https://api.bamboohr.com/api/gateway.php/${connectionConfig.subdomain} - docs: https://docs.nango.dev/integrations/all/bamboohr - connection_config: - subdomain: - type: string - title: BambooHR Domain - description: The subdomain of your BambooHR account - pattern: '^[a-z0-9_-]+$' - example: domain - suffix: .bamboohr.com - prefix: https:// - order: 1 - -bamboohr-basic: - display_name: BambooHR (basic auth) - categories: - - hr - auth_mode: BASIC - proxy: - base_url: https://api.bamboohr.com/api/gateway.php/${connectionConfig.subdomain} - verification: - method: GET - endpoint: /v1/meta/fields - docs: https://docs.nango.dev/integrations/all/bamboohr - docs_connect: https://docs.nango.dev/integrations/all/bamboohr-basic/connect - connection_config: - subdomain: - type: string - title: BambooHR Domain - description: The subdomain of your BambooHR account - pattern: '^[a-z0-9_-]+$' - example: domain - suffix: .bamboohr.com - prefix: https:// - order: 1 - doc_section: '#step-1-finding-your-subdomain' - credentials: - username: - type: string - title: API key - description: The API Key of your BambooHR account - pattern: '^[a-zA-Z0-9]+$' - secret: true - doc_section: '#step-2-finding-your-api-key' - password: - type: string - title: Password - description: Password - # https://documentation.bamboohr.com/docs/getting-started - # Bamboo HR is using basic auth with an api key - default_value: x - hidden: true - -battlenet: - display_name: Battle.net - categories: - - gaming - auth_mode: OAUTH2 - authorization_url: https://oauth.battle.${connectionConfig.extension}/authorize - token_url: https://oauth.battle.${connectionConfig.extension}/token - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - proxy: - base_url: https://${connectionConfig.apiDomain} - docs: https://docs.nango.dev/integrations/all/battlenet - connection_config: - extension: - type: string - title: Domain Extension - description: The domain extension of your Battle.net account - example: com - pattern: '^[a-z.]+$' - order: 1 - apiDomain: - type: string - title: API Domain - description: The domain to where you will access your API - example: us.api.blizzard.com - pattern: '^[a-z.]+$' - prefix: https:// - -beehiiv: - display_name: Beehiiv - categories: - - communication - - marketing - auth_mode: API_KEY - proxy: - headers: - authorization: Bearer ${apiKey} - base_url: https://api.beehiiv.com/v2/publications/${connectionConfig.publicationId} - verification: - method: GET - endpoint: /posts - docs: https://docs.nango.dev/integrations/all/beehiiv - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Beehiiv account - example: 8ab3sjxqvHzyUnP9JhvlfT6C0wsbgr5XQrpaZZjxJkYBPy6sntvT1M2Lk94VQeRb - pattern: '^[a-zA-Z0-9]{64}$' - connection_config: - publicationId: - type: string - title: Publication Id - description: The prefixed ID of the publication object - example: pub_a3d1b49e-2a5d-4f4b-97c8-8f32e1d2f7b9 - pattern: '^(pub_[0-9a-fA-F\-]+)$' - -bigcommerce: - display_name: BigCommerce - categories: - - e-commerce - auth_mode: OAUTH2 - authorization_url: https://login.bigcommerce.com/oauth2/authorize - token_url: https://login.bigcommerce.com/oauth2/token - scope_separator: ' ' - authorization_params: - response_type: code - context: stores/${connectionConfig.storeHash} - account_uuid: ${connectionConfig.accountUuid} - token_params: - context: stores/${connectionConfig.storeHash} - grant_type: authorization_code - proxy: - base_url: https://api.bigcommerce.com/stores/${connectionConfig.storeHash} - docs: https://docs.nango.dev/integrations/all/bigcommerce - connection_config: - storeHash: - type: string - title: Store Hash - description: The store hash of your BigCommerce account - pattern: '^[a-zA-Z0-9]+$' - accountUuid: - type: string - title: Account UUID - description: The account UUID of your BigCommerce account - format: uuid - example: 123e4567-e89b-12d3-a456-426614174000 - -bill-sandbox: - display_name: Bill (Connect API sandbox) - categories: - - payment - auth_mode: BILL - token_url: https://gateway.stage.bill.com/connect/v3/login - proxy: - base_url: https://gateway.stage.bill.com/connect - docs: https://docs.nango.dev/integrations/all/bill - docs_connect: https://docs.nango.dev/integrations/all/bill-sandbox/connect - -bill: - display_name: Bill (Connect API) - categories: - - payment - auth_mode: BILL - token_url: https://gateway.prod.bill.com/connect/v3/login - proxy: - base_url: https://gateway.prod.bill.com/connect - docs: https://docs.nango.dev/integrations/all/bill - -bitbucket: - display_name: Bitbucket - categories: - - dev-tools - auth_mode: OAUTH2 - authorization_url: https://bitbucket.org/site/oauth2/authorize - token_url: https://bitbucket.org/site/oauth2/access_token - proxy: - base_url: https://api.bitbucket.org - docs: https://docs.nango.dev/integrations/all/bitbucket - -bitdefender: - display_name: Bitdefender - categories: - - other - auth_mode: BASIC - proxy: - base_url: ${connectionConfig.ACCESS_URL} - retry: - after: 'retry-after' - docs: https://docs.nango.dev/integrations/all/bitdefender - docs_connect: https://docs.nango.dev/integrations/all/bitdefender/connect - credentials: - username: - type: string - title: API Key - description: The API Key of your Bitdefender account - doc_section: '#step-1-finding-your-api-key' - password: - type: string - title: '' - description: '' - default_value: '' - hidden: true - connection_config: - ACCESS_URL: - type: string - title: Access URL - description: The access URL of your Bitdefender account - example: https://api.bitdefender.com - format: uri - pattern: '^https://.*' - doc_section: '#step-1-finding-your-api-key' - -bitly: - display_name: Bitly - categories: - - marketing - - social - auth_mode: OAUTH2 - authorization_url: https://bitly.com/oauth/authorize - token_url: https://api-ssl.bitly.com/oauth/access_token - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - proxy: - base_url: https://api-ssl.bitly.com - docs: https://docs.nango.dev/integrations/all/bitly - -blackbaud: - display_name: Blackbaud - categories: - - crm - auth_mode: OAUTH2 - authorization_url: https://app.blackbaud.com/oauth/authorize - token_url: https://oauth2.sky.blackbaud.com/token - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://api.sky.blackbaud.com - docs: https://docs.nango.dev/integrations/all/blackbaud - -blandai: - display_name: BlandAI - categories: - - support - auth_mode: API_KEY - proxy: - base_url: https://api.bland.ai - headers: - authorization: ${apiKey} - docs: https://docs.nango.dev/integrations/all/blandai - credentials: - apiKey: - type: string - title: API Key - description: The API key for your BlandAI account - -boldsign: - display_name: BoldSign - categories: - - legal - auth_mode: OAUTH2 - authorization_url: https://account.boldsign.com/connect/authorize - token_url: https://account.boldsign.com/connect/token - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://api.boldsign.com - docs: https://docs.nango.dev/integrations/all/boldsign - -box: - display_name: Box - categories: - - knowledge-base - - storage - auth_mode: OAUTH2 - authorization_url: https://account.box.com/api/oauth2/authorize - token_url: https://api.box.com/oauth2/token - proxy: - base_url: https://api.box.com - docs: https://docs.nango.dev/integrations/all/box - -booking-com: - display_name: Booking.com - categories: - - e-commerce - auth_mode: BASIC - proxy: - base_url: https://${connectionConfig.environmentType}-xml.booking.com - docs: https://docs.nango.dev/integrations/all/booking-com - connection_config: - environmentType: - type: string - title: Environment Type - description: The environment type for your various requests - pattern: '^(secure-supply|supply)$' - example: secure-supply|supply - suffix: -xml.booking.com - prefix: https:// - -braintree: - display_name: Braintree - categories: - - payment - auth_mode: OAUTH2 - authorization_url: https://api.braintreegateway.com/oauth/connect - token_url: https://api.braintreegateway.com/oauth/access_tokens - scope_separator: ',' - authorization_method: header - body_format: json - token_params: - grant_type: authorization_code - redirect_uri_metadata: - - merchantId - proxy: - base_url: https://api.braintreegateway.com - docs: https://docs.nango.dev/integrations/all/braintree - -braintree-sandbox: - display_name: Braintree (sandbox) - auth_mode: OAUTH2 - authorization_url: https://api.sandbox.braintreegateway.com/oauth/connect - token_url: https://api.sandbox.braintreegateway.com/oauth/access_tokens - scope_separator: ',' - authorization_method: header - body_format: json - token_params: - grant_type: authorization_code - redirect_uri_metadata: - - merchantId - proxy: - base_url: https://api.sandbox.braintreegateway.com - docs: https://docs.nango.dev/integrations/all/braintree - -braze: - display_name: Braze - categories: - - communication - auth_mode: API_KEY - proxy: - base_url: https://rest.${connectionConfig.instanceUrl} - headers: - authorization: Bearer ${apiKey} - retry: - at: 'x-ratelimit-reset' - docs: https://docs.nango.dev/integrations/all/braze - docs_connect: https://docs.nango.dev/integrations/all/braze/connect - connection_config: - instanceUrl: - type: string - title: Instance URL - description: The REST API URL of your Braze instance - example: iad-02.braze.com - format: hostname - prefix: https://rest. - order: 1 - doc_section: '#step-1-finding-your-instance-url' - credentials: - apiKey: - type: string - title: API Key - description: The API key to your Braze account - doc_section: '#step-2-finding-your-api-key' - -brevo-api-key: - display_name: Brevo (api key) - categories: - - marketing - auth_mode: API_KEY - proxy: - headers: - api-key: ${apiKey} - base_url: https://api.brevo.com/v3 - docs: https://docs.nango.dev/integrations/all/brevo - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Brevo account - -brex: - display_name: Brex - categories: - - banking - auth_mode: OAUTH2 - authorization_url: https://accounts-api.brex.com/oauth2/default/v1/authorize - token_url: https://accounts-api.brex.com/oauth2/default/v1/token - default_scopes: - - openid - - offline_access - proxy: - base_url: https://platform.brexapis.com - docs: https://docs.nango.dev/integrations/all/brex - -brex-api-key: - display_name: Brex (api key) - auth_mode: API_KEY - proxy: - headers: - authorization: Bearer ${apiKey} - base_url: https://platform.brexapis.com - docs: https://docs.nango.dev/integrations/all/brex - docs_connect: https://docs.nango.dev/integrations/all/brex-api-key/connect - credentials: - apiKey: - type: string - title: API Token - description: The API Token to your Brex account - example: bxt_vRUwQT3snBmA1IDVq5iK1kXc4N0bhxr377z4 - pattern: '^bxt_[a-zA-Z0-9]+$' - doc_section: '#step-1-finding-your-api-token' - -brex-staging: - display_name: Brex (staging) - auth_mode: OAUTH2 - authorization_url: https://accounts-api.staging.brexapps.com/oauth2/default/v1/authorize - token_url: https://accounts-api.staging.brexapps.com/oauth2/default/v1/token - proxy: - base_url: https://platform.staging.brexapis.com - docs: https://docs.nango.dev/integrations/all/brex - -brightcrowd: - display_name: BrightCrowd - categories: - - social - auth_mode: OAUTH2_CC - token_url: https://bcb-staging.auth.us-east-1.amazoncognito.com/oauth2/token - token_request_auth_method: basic - token_params: - grant_type: client_credentials - proxy: - base_url: https://api.brightcrowd.com/partner - paginate: - type: cursor - cursor_path_in_response: nextPageToken - cursor_name_in_request: pageToken - docs: https://docs.nango.dev/integrations/all/brightcrowd - docs_connect: https://docs.nango.dev/integrations/all/brightcrowd/connect - -builder-io-private: - display_name: Builder.io (private) - categories: - - dev-tools - - design - - cms - auth_mode: API_KEY - proxy: - base_url: https://${connectionConfig.domain} - headers: - authorization: Bearer ${apiKey} - docs: https://docs.nango.dev/integrations/all/builder-io - docs_connect: https://docs.nango.dev/integrations/all/builder-io-private/connect - connection_config: - domain: - type: string - title: Domain - description: The domain used to access your Builder.io API - example: cdn.builder.io - format: hostname - prefix: https:// - doc_section: '#step-1-finding-your-api-domain' - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Builder.io account - pattern: '^[a-zA-Z0-9]+$' - example: bb209fb71eh2412dbe0114bdae18fd15 - doc_section: '#step-2-finding-your-api-key' - -builder-io-public: - display_name: Builder.io (public) - categories: - - dev-tools - - design - - cms - auth_mode: API_KEY - proxy: - base_url: https://${connectionConfig.domain} - query: - apiKey: ${apiKey} - docs: https://docs.nango.dev/integrations/all/builder-io - docs_connect: https://docs.nango.dev/integrations/all/builder-io-public/connect - connection_config: - domain: - type: string - title: Domain - description: The domain used to access your Builder.io API - example: builder.io - format: hostname - prefix: https:// - doc_section: '#step-1-finding-your-api-domain' - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Builder.io account - pattern: '^[a-zA-Z0-9]+$' - example: bb209fb71eh2412dbe0114bdae18fd15 - doc_section: '#step-2-finding-your-api-key' - -buildium: - display_name: Buildium - categories: - - accounting - - crm - - payment - auth_mode: API_KEY - proxy: - base_url: https://api.buildium.com - headers: - x-buildium-client-id: ${connectionConfig.clientId} - x-buildium-client-secret: ${apiKey} - verification: - method: GET - endpoint: /v1/rentals - docs: https://docs.nango.dev/integrations/all/buildium - docs_connect: https://docs.nango.dev/integrations/all/buildium/connect - connection_config: - clientId: - type: string - title: Client ID - description: Your API Key Client ID - pattern: '^[a-f0-9-]+$' - example: a228f0e7-b4a3-4150-b9ae-8552fc2880d3 - doc_section: '#step-2-finding-your-client-id-and-secret' - order: 1 - credentials: - apiKey: - type: string - title: Secret - description: The Secret for your Buildium account - pattern: '^[A-Za-z0-9+/]+$' - example: uOq2p+xlgpFdijfV/HqY+EvYpZKHRwlyhGuAVbJIxXs - doc_section: '#step-2-finding-your-client-id-and-secret' - -builtwith: - display_name: BuiltWith - categories: - - dev-tools - - analytics - - crm - - marketing - - e-commerce - auth_mode: API_KEY - proxy: - base_url: https://api.builtwith.com - query: - KEY: ${apiKey} - docs: https://docs.nango.dev/integrations/all/builtwith - docs_connect: https://docs.nango.dev/integrations/all/builtwith/connect - credentials: - apiKey: - type: string - title: API Key - description: The API key for your BuiltWith account - example: 1bc32cba-a5d6-438a-bbcc-af312f560a3c - format: uuid - doc_section: '#step-1-finding-your-api-key' - -cal-com-v1: - display_name: Cal.com (v1) - categories: - - productivity - auth_mode: API_KEY - proxy: - base_url: https://api.cal.com/v1 - query: - apiKey: ${apiKey} - retry: - at: 'x-ratelimit-reset' - verification: - method: GET - endpoint: /me - docs: https://docs.nango.dev/integrations/all/cal-com - docs_connect: https://docs.nango.dev/integrations/all/cal-com-v1/connect - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Cal.com account - pattern: '^cal_[a-zA-Z0-9_]+$' - example: cal_xxxxxx - doc_section: '#step-1-finding-your-api-key' -cal-com-v2: - display_name: Cal.com (v2) - categories: - - productivity - auth_mode: API_KEY - proxy: - base_url: https://api.cal.com/v2 - headers: - authorization: Bearer ${apiKey} - paginate: - type: cursor - cursor_name_in_request: cursor - cursor_path_in_response: data.data.nextCursor - limit_name_in_request: limit - retry: - at: 'x-ratelimit-reset' - verification: - method: GET - endpoint: /me - docs: https://docs.nango.dev/integrations/all/cal-com - docs_connect: https://docs.nango.dev/integrations/all/cal-com-v2/connect - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Cal.com account - pattern: '^cal_[a-zA-Z0-9_]+$' - example: cal_xxxxxx - doc_section: '#step-1-finding-your-api-key' - -calendly: - display_name: Calendly - categories: - - productivity - auth_mode: OAUTH2 - authorization_url: https://auth.calendly.com/oauth/authorize - token_url: https://auth.calendly.com/oauth/token - authorization_params: - response_type: code - proxy: - base_url: https://api.calendly.com - paginate: - type: link - link_path_in_response_body: pagination.next_page - retry: - at: 'x-ratelimit-reset' - token_response_metadata: - - owner - post_connection_script: calendlyPostConnection - docs: https://docs.nango.dev/integrations/all/calendly - -canny: - display_name: Canny - categories: - - support - auth_mode: API_KEY - proxy: - base_url: https://canny.io/api/v1 - query: - apiKey: ${apiKey} - verification: - method: POST - endpoint: /boards/list - docs: https://docs.nango.dev/integrations/all/canny - docs_connect: https://docs.nango.dev/integrations/all/canny/connect - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Canny account - example: a1f5937c-82df-bd29-4e3a-7b6fda8c54d1 - pattern: '^[a-zA-Z0-9-]+$' - doc_section: '#step-1-finding-your-api-key' -canva-scim: - display_name: Canva (SCIM API) - categories: - - design - - dev-tools - auth_mode: API_KEY - proxy: - base_url: https://www.canva.com/_scim - headers: - authorization: Bearer ${apiKey} - accept: application/json - content-type: application/json - docs: https://docs.nango.dev/integrations/all/canva - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Canva scim account - doc_section: '#step-1-finding-canva-api-key' - -certn: - display_name: Certn - categories: - - legal - auth_mode: API_KEY - proxy: - base_url: https://api.certn.co - headers: - authorization: Bearer ${apiKey} - paginate: - type: link - link_path_in_response_body: next - response_path: results - verification: - method: GET - endpoint: /api/v2/teams - docs: https://docs.nango.dev/integrations/all/certn - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Certn account - -certn-partner: - display_name: Certn Partner - categories: - - legal - auth_mode: OAUTH2_CC - proxy: - headers: - authorization: Bearer ${apiKey} - base_url: https://api.certn.co - paginate: - type: offset - offset_name_in_request: page - response_path: data - limit_name_in_request: limit - verification: - method: GET - endpoint: /api/v2/teams - docs: https://docs.nango.dev/integrations/all/certn - -chargebee: - display_name: Chargebee - categories: - - payment - auth_mode: BASIC - proxy: - base_url: https://${connectionConfig.subdomain}.chargebee.com - verification: - method: GET - endpoint: /api/v2/business_entities - retry: - after: 'retry-after' - docs: https://docs.nango.dev/integrations/all/chargebee - connection_config: - subdomain: - type: string - title: Chargebee Domain - description: The subdomain of your Chargebee account - pattern: '^[a-z0-9_-]+$' - example: domain - suffix: .chargebee.com - prefix: https:// - -chattermill: - display_name: Chattermill - categories: - - support - - analytics - auth_mode: API_KEY - proxy: - base_url: https://${connectionConfig.subdomain}.chattermill.com - headers: - authorization: Bearer ${apiKey} - accept: application/json - content-type: application/json - docs: https://docs.nango.dev/integrations/all/chattermill - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Chattermill account - connection_config: - subdomain: - type: string - title: Chattermill subdomain - description: The subdomain for your api requests - pattern: '^(app|api|backend)$' - example: 'app|api|backend' - suffix: .chattermill.com - prefix: https:// - -checkr-partner: - display_name: Checkr Partner - categories: - - legal - auth_mode: OAUTH2 - authorization_url: https://partners.checkr.com/authorize/${connectionConfig.client_id} - token_url: https://api.checkr.com/oauth/tokens - disable_pkce: true - token_params: - grant_type: authorization_code - proxy: - retry: - at: 'x-ratelimit-reset' - base_url: https://api.checkr.com - token_response_metadata: - - checkr_account_id - webhook_routing_script: checkrWebhookRouting - post_connection_script: checkrPostConnection - docs: https://docs.nango.dev/integrations/all/checkr-partner - connection_config: - client_id: - type: string - title: Client ID - description: The client ID of your Checkr Partner account - -checkr-partner-staging: - display_name: Checkr Partner (staging) - categories: - - legal - auth_mode: OAUTH2 - authorization_url: https://partners.checkrhq-staging.net/authorize/${connectionConfig.client_id} - token_url: https://api.checkr-staging.com/oauth/tokens - disable_pkce: true - token_params: - grant_type: authorization_code - proxy: - retry: - at: 'x-ratelimit-reset' - base_url: https://api.checkr-staging.com - token_response_metadata: - - checkr_account_id - webhook_routing_script: checkrWebhookRouting - post_connection_script: checkrPostConnection - docs: https://docs.nango.dev/integrations/all/checkr-partner - connection_config: - client_id: - type: string - title: Client ID - description: The client ID of your Checkr Partner account - -checkout-com: - display_name: Checkout.com - categories: - - payment - auth_mode: OAUTH2_CC - token_url: https://access.checkout.com/connect/token - token_request_auth_method: basic - token_params: - grant_type: client_credentials - proxy: - headers: - content-type: application/json - accept: application/json - base_url: https://api.checkout.com - docs: https://docs.nango.dev/integrations/all/checkout-com - -checkout-com-sandbox: - display_name: Checkout.com (sandbox) - categories: - - payment - auth_mode: OAUTH2_CC - token_url: https://access.sandbox.checkout.com/connect/token - token_request_auth_method: basic - token_params: - grant_type: client_credentials - proxy: - headers: - content-type: application/json - accept: application/json - base_url: https://api.sandbox.checkout.com - docs: https://docs.nango.dev/integrations/all/checkout-com - -chorus: - display_name: Chorus - auth_mode: API_KEY - proxy: - base_url: https://chorus.ai - verification: - method: GET - endpoint: /api/v1/users/me - headers: - authorization: Bearer ${apiKey} - docs: https://docs.nango.dev/integrations/all/chorus - docs_connect: https://docs.nango.dev/integrations/all/chorus/connect - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Chorus account - doc_section: '#step-1-generating-your-chorus-api-key' - -circle-so: - display_name: Circle.so - categories: - - communication - auth_mode: API_KEY - proxy: - base_url: https://app.circle.so - headers: - authorization: Token ${apiKey} - docs: https://docs.nango.dev/integrations/all/circle-so - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Circle.so account - -clari-copilot: - display_name: Clari Copilot - categories: - - marketing - auth_mode: API_KEY - proxy: - headers: - x-api-key: ${apiKey} - x-api-password: ${connectionConfig.API_PASSWORD} - base_url: https://rest-api.copilot.clari.com - docs: https://docs.nango.dev/integrations/all/clari-copilot - connection_config: - API_PASSWORD: - type: string - title: API Password - description: The API password of your Clari Copilot account - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Clari Copilot account - -clickup: - display_name: ClickUp - categories: - - productivity - - ticketing - auth_mode: OAUTH2 - authorization_url: https://app.clickup.com/api - token_url: https://api.clickup.com/api/v2/oauth/token - proxy: - base_url: https://api.clickup.com - docs: https://docs.nango.dev/integrations/all/clickup - -cloudentity: - display_name: Cloudentity - auth_mode: OAUTH2_CC - categories: - - other - token_url: https://${connectionConfig.tenantID}.${connectionConfig.regionID}.authz.cloudentity.io/${connectionConfig.tenantID}/${connectionConfig.workspaceID}/oauth2/token - scope_separator: ' ' - token_params: - grant_type: client_credentials - proxy: - base_url: https://${connectionConfig.tenantID}.${connectionConfig.regionID}.authz.cloudentity.io/${connectionConfig.tenantID}/${connectionConfig.workspaceID} - docs: https://docs.nango.dev/integrations/all/cloudentity - connection_config: - tenantID: - type: string - title: Tenant ID - description: The tenant ID of your Cloudentity account - regionID: - type: string - title: Region ID - description: The region ID of your Cloudentity account - workspaceID: - type: string - title: Workspace ID - description: The workspace ID of your Cloudentity account - -close: - display_name: Close - categories: - - crm - auth_mode: OAUTH2 - authorization_url: https://app.close.com/oauth2/authorize - token_url: https://api.close.com/oauth2/token/ - authorization_params: - response_type: code - default_scopes: - - offline_access - proxy: - base_url: https://api.close.com/api - docs: https://docs.nango.dev/integrations/all/close - -coda: - display_name: Coda - categories: - - knowledge-base - - productivity - auth_mode: API_KEY - proxy: - base_url: https://coda.io/apis/v1 - headers: - authorization: Bearer ${apiKey} - docs: https://docs.nango.dev/integrations/all/coda - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Coda account - -codeclimate: - display_name: Code Climate - categories: - - dev-tools - - productivity - auth_mode: API_KEY - proxy: - base_url: https://${connectionConfig.domain} - headers: - accept: application/vnd.api+json - authorization: Token token=${apiKey} - verification: - method: GET - endpoint: /v1/user - docs: https://docs.nango.dev/integrations/all/codeclimate - connection_config: - domain: - type: string - title: Domain - description: The domain of your Code Climate account - format: hostname - prefix: https:// - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Code Climate account - -copper: - display_name: Copper - categories: - - crm - auth_mode: OAUTH2 - proxy: - base_url: https://api.copper.com/developer_api - default_scopes: - - developer/v1/all - authorization_url: https://app.copper.com/oauth/authorize - token_url: https://app.copper.com/oauth/token - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - docs: https://docs.nango.dev/integrations/all/copper - -copper-api-key: - display_name: Copper (api key) - categories: - - crm - auth_mode: API_KEY - proxy: - base_url: https://api.copper.com/developer_api - headers: - x-pw-accesstoken: ${apiKey} - x-pw-application: developer_api - x-pw-useremail: ${connectionConfig.userEmail} - content-type: application/json - verification: - method: GET - endpoint: /v1/account - docs_connect: https://docs.nango.dev/integrations/all/copper/connect - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Copper account - pattern: '^[a-f0-9]{32}$' - example: '4f3c12efb9659a0b5c123b568745dbf9' - doc_section: '#step-1-finding-copper-api-key' - connection_config: - userEmail: - type: string - title: User Email - description: Email address of the user who generated the token - docs: https://docs.nango.dev/integrations/all/copper - -connectwise-psa: - display_name: ConnectWise PSA - categories: - - support - - ticketing - auth_mode: BASIC - proxy: - base_url: https://${connectionConfig.subdomain}.myconnectwise.net/v4_6_release/apis/3.0 - headers: - accept: application/vnd.connectwise.com+json; version=${connectionConfig.apiVersion} - clientid: ${connectionConfig.clientId} - docs: https://docs.nango.dev/integrations/all/connectwise-psa - connection_config: - subdomain: - type: string - title: ConnectWise PSA subdomain - description: The subdomain to connect to ConnectWise PSA - pattern: '^api-(au|eu|na)$' - example: api-au - suffix: .myconnectwise.net - prefix: https:// - apiVersion: - type: string - title: Api version - description: The API version to connect to ConnectWise PSA - clientId: - type: string - title: Client ID - description: The Client ID assigned to your integration - -connectwise-psa-staging: - display_name: ConnectWise PSA (staging) - categories: - - support - - ticketing - auth_mode: BASIC - proxy: - base_url: https://api-staging.connectwisedev.com/v4_6_release/apis/3.0 - headers: - accept: application/vnd.connectwise.com+json; version=${connectionConfig.apiVersion} - clientid: ${connectionConfig.clientId} - docs: https://docs.nango.dev/integrations/all/connectwise-psa - connection_config: - apiVersion: - type: string - title: Api version - description: The API version to connect to ConnectWise PSA - clientId: - type: string - title: Client ID - description: The Client ID assigned to your integration - -confluence: - display_name: Confluence - categories: - - knowledge-base - alias: jira - docs: https://docs.nango.dev/integrations/all/confluence - -contentful: - display_name: Contentful - categories: - - dev-tools - - design - - cms - auth_mode: OAUTH2 - authorization_url: https://be.contentful.com/oauth/authorize - token_url: https://be.contentful.com/oauth/token - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://${connectionConfig.subdomain}.contentful.com - retry: - after: x-contentful-ratelimit-reset - docs: https://docs.nango.dev/integrations/all/contentful - connection_config: - subdomain: - type: string - title: Contentful Domain - description: The subdomain of your Contentful account - pattern: '^[a-z0-9_-]+$' - example: domain - suffix: .contentful.com - prefix: https:// - -contentstack: - display_name: Contentstack - categories: - - cms - auth_mode: OAUTH2 - authorization_url: https://${connectionConfig.subdomain}.contentstack.com/apps/${connectionConfig.appId}/authorize - token_url: https://${connectionConfig.subdomain}.contentstack.com/apps-api/apps/token - docs: https://docs.nango.dev/integrations/all/contentstack - proxy: - base_url: https://${connectionConfig.apiDomain} - connection_config: - subdomain: - type: string - title: Contentstack Domain - description: The subdomain of your Contentstack account - pattern: '^[a-z0-9_-]+$' - example: domain - suffix: .contentstack.com - prefix: https:// - order: 2 - appId: - type: string - title: App ID - description: The app ID of your Contentstack account - order: 1 - apiDomain: - type: string - title: API Domain - description: The domain to where you will access your API - pattern: '^[a-z0-9_-]+$' - example: eu-api.contentstack.com - prefix: https:// - order: 3 - -coros: - display_name: Coros - categories: - - sports - auth_mode: OAUTH2 - authorization_url: https://open.coros.com/oauth2/authorize - token_url: https://open.coros.com/oauth2/accesstoken - refresh_url: https://open.coros.com/oauth2/refresh-token - authorization_params: - response_type: code - token_response_metadata: - - openId - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://open.coros.com - docs: https://docs.nango.dev/integrations/all/coros - -coros-sandbox: - display_name: Coros (sandbox) - auth_mode: OAUTH2 - authorization_url: https://opentest.coros.com/oauth2/authorize - token_url: https://opentest.coros.com/oauth2/accesstoken - refresh_url: https://opentest.coros.com/oauth2/refresh-token - authorization_params: - response_type: code - token_response_metadata: - - openId - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://opentest.coros.com - docs: https://docs.nango.dev/integrations/all/coros - -coupa-compass: - display_name: Coupa Compass - categories: - - payment - - invoicing - auth_mode: OAUTH2_CC - scope_separator: ' ' - token_url: https://${connectionConfig.instanceDomain}/oauth2/token - token_params: - grant_type: client_credentials - proxy: - base_url: https://${connectionConfig.instanceDomain} - docs: https://docs.nango.dev/integrations/all/coupa-compass - connection_config: - instanceDomain: - type: string - title: Instance Domain - description: The domain of your Coupa Compass account - format: hostname - prefix: https:// - -databricks-account: - display_name: Databricks (Account Level) - categories: - - analytics - auth_mode: OAUTH2_CC - token_url: https://accounts.cloud.databricks.com/oidc/accounts/${connectionConfig.accountId}/v1/token - token_params: - grant_type: client_credentials - proxy: - base_url: https://accounts.cloud.databricks.com/api/2.0/accounts/${connectionConfig.accountId} - docs: https://docs.nango.dev/integrations/all/databricks - connection_config: - accountId: - type: string - title: Account ID - description: The ID to your account - format: uuid - example: 123e4567-e89b-12d3-a456-426614174000 - -databricks-workspace: - display_name: Databricks (Workspace Level) - categories: - - analytics - auth_mode: OAUTH2_CC - token_url: https://${connectionConfig.databricksInstance}/oidc/v1/token - token_params: - grant_type: client_credentials - proxy: - base_url: https://${connectionConfig.databricksInstance}/api/2.0/ - docs: https://docs.nango.dev/integrations/all/databricks - connection_config: - databricksInstance: - type: string - title: Databricks Instance - description: The instance to your databricks deployment - pattern: '^[a-z0-9_-]+(\.[a-z0-9_-]+)*$' - example: dbc-a1b2345c-d6e7.cloud.databricks.com - -# Untested configuration. Please reach out if you have a test account that we can use to test it. -datev: - display_name: Datev - categories: - - legal - - hr - auth_mode: OAUTH2 - authorization_url: https://login.datev.de/openid/authorize - token_url: https://api.datev.de/token - token_request_auth_method: basic - scope_separator: ' ' - default_scopes: - - openid - authorization_params: - response_type: code id_token - response_mode: query - nonce: AnotherRandomStringDatev - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://api.datev.de - docs: https://docs.nango.dev/integrations/all/datev - -datadog: - display_name: Datadog - categories: - - analytics - - dev-tools - auth_mode: API_KEY - proxy: - base_url: https://api.${connectionConfig.siteParameter}/api - headers: - dd-api-key: ${apiKey} - dd-application-key: ${connectionConfig.applicationKey} - verification: - method: GET - endpoint: /v1/validate - retry: - after: 'x-ratelimit-reset' - docs: https://docs.nango.dev/integrations/all/datadog - docs_connect: https://docs.nango.dev/integrations/all/datadog/connect - connection_config: - siteParameter: - type: string - title: Site Parameter - description: The site parameter to datadog - pattern: '^(us[35]\.)?(ap1\.)?(datadoghq\.(com|eu)|ddog-gov\.com)$' - example: 'us5.datadoghq.com' - doc_section: '#step-1-finding-your-datadog-domain' - applicationKey: - type: string - title: Application Key - description: The application key required for read data access - pattern: '^[a-f0-9]{40}$' - example: '5d8a7b3f2dc8bce1b234e7f1a1ac54728dbf9e4a7' - doc_section: '#step-3-datadog-application-key' - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Datadog account - pattern: '^[a-f0-9]{32}$' - example: '4f3c12efb9659a0b5c123b568745dbf9' - doc_section: '#step-2-datadog-api-key' - -deel: - display_name: Deel - categories: - - hr - auth_mode: OAUTH2 - authorization_url: https://auth.letsdeel.com/oauth2/authorize - token_url: https://auth.letsdeel.com/oauth2/tokens - token_request_auth_method: basic - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://api.letsdeel.com - docs: https://docs.nango.dev/integrations/all/deel - -deel-sandbox: - display_name: Deel (sandbox) - auth_mode: OAUTH2 - authorization_url: https://auth-demo.letsdeel.com/oauth2/authorize - token_url: https://auth-demo.letsdeel.com/oauth2/tokens - token_request_auth_method: basic - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://api-staging.letsdeel.com - docs: https://docs.nango.dev/integrations/all/deel - -dialpad: - display_name: Dialpad - categories: - - communication - auth_mode: OAUTH2 - authorization_url: https://dialpad.com/oauth2/authorize - token_url: https://dialpad.com/oauth2/token - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://dialpad.com - docs: https://docs.nango.dev/integrations/all/dialpad - -dialpad-sandbox: - display_name: Dialpad (sandbox) - categories: - - communication - auth_mode: OAUTH2 - authorization_url: https://sandbox.dialpad.com/oauth2/authorize - token_url: https://sandbox.dialpad.com/oauth2/token - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://sandbox.dialpad.com - docs: https://docs.nango.dev/integrations/all/dialpad - -digitalocean: - display_name: DigitalOcean - categories: - - dev-tools - auth_mode: OAUTH2 - authorization_url: https://cloud.digitalocean.com/v1/oauth/authorize - token_url: https://cloud.digitalocean.com/v1/oauth/token - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://api.digitalocean.com - docs: https://docs.nango.dev/integrations/all/digitalocean - -discord: - display_name: Discord - categories: - - gaming - - social - auth_mode: OAUTH2 - authorization_url: https://discord.com/api/oauth2/authorize - token_url: https://discord.com/api/oauth2/token - authorization_params: - response_type: code - proxy: - base_url: https://discord.com - retry: - after: 'retry-after' - docs: https://docs.nango.dev/integrations/all/discord - -discourse: - display_name: Discourse - categories: - - communication - auth_mode: API_KEY - proxy: - base_url: https://${connectionConfig.defaultHost} - retry: - after: 'retry-after' - headers: - api-username: ${connectionConfig.apiUsername} - api-key: ${apiKey} - accept: application/json - docs: https://docs.nango.dev/integrations/all/discourse - connection_config: - defaultHost: - type: string - title: Domain - description: The domain of your Discourse account - format: hostname - prefix: https:// - apiUsername: - type: string - title: API Username - description: The API username of your Discourse account - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Discourse account - -dixa: - display_name: Dixa - categories: - - support - auth_mode: API_KEY - proxy: - base_url: https://${connectionConfig.apiType}.dixa.io - headers: - authorization: ${apiKey} - docs: https://docs.nango.dev/integrations/all/dixa - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Dixa account - connection_config: - apiType: - type: string - title: Api Type - description: The Api type for your requests - pattern: '^dev\|exports$' - example: 'dev|exports' - -docusign: - display_name: DocuSign - categories: - - legal - auth_mode: OAUTH2 - authorization_url: https://account.docusign.com/oauth/auth - token_url: https://account.docusign.com/oauth/token - token_request_auth_method: basic - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://www.docusign.net - post_connection_script: docusignPostConnection - docs: https://docs.nango.dev/integrations/all/docusign - -docusign-sandbox: - display_name: DocuSign (sandbox) - auth_mode: OAUTH2 - authorization_url: https://account-d.docusign.com/oauth/auth - token_url: https://account-d.docusign.com/oauth/token - token_request_auth_method: basic - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://demo.docusign.net - post_connection_script: docusignPostConnection - docs: https://docs.nango.dev/integrations/all/docusign - -dropbox: - display_name: Dropbox - categories: - - knowledge-base - - storage - auth_mode: OAUTH2 - authorization_url: https://www.dropbox.com/oauth2/authorize - token_url: https://api.dropboxapi.com/oauth2/token - authorization_params: - token_access_type: offline - proxy: - base_url: https://api.dropboxapi.com - docs: https://docs.nango.dev/integrations/all/dropbox - -emarsys: - display_name: Emarsys Core API (WSSE) - categories: - - marketing - auth_mode: SIGNATURE - signature: - protocol: WSSE - proxy: - base_url: https://api.emarsys.net - headers: - content-type: application/json - x-wsse: ${accessToken} - verification: - method: GET - endpoint: /api/v2/settings - retry: - at: 'x-ratelimit-reset' - token: - expires_in_ms: 300000 - docs: https://docs.nango.dev/integrations/all/emarsys - credentials: - username: - type: string - title: ID - description: The ID of your Emarsys WSSE API Credentials - pattern: '^[a-zA-Z0-9_-]+$' - password: - type: string - title: Client Secret - description: The Client Secret of your Emarsys WSSE API Credentials - pattern: '^[a-zA-Z0-9-]+$' - -emarsys-oauth: - display_name: Emarsys (Ouath) - categories: - - marketing - auth_mode: OAUTH2_CC - token_url: https://auth.emarsys.net/oauth2/token - token_request_auth_method: basic - token_params: - grant_type: client_credentials - proxy: - base_url: https://api.emarsys.net - retry: - at: 'x-ratelimit-reset' - docs: https://docs.nango.dev/integrations/all/emarsys - -ebay: - display_name: eBay - categories: - - e-commerce - auth_mode: OAUTH2 - authorization_url: https://auth.ebay.com/oauth2/authorize - token_url: https://api.ebay.com/identity/v1/oauth2/token - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - token_request_auth_method: basic - proxy: - base_url: https://api.ebay.com/ - docs: https://docs.nango.dev/integrations/all/ebay - -ebay-sandbox: - display_name: eBay (sandbox) - categories: - - e-commerce - auth_mode: OAUTH2 - authorization_url: https://auth.sandbox.ebay.com/oauth2/authorize - token_url: https://api.sandbox.ebay.com/identity/v1/oauth2/token - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - token_request_auth_method: basic - proxy: - base_url: https://api.sandbox.ebay.com/ - docs: https://docs.nango.dev/integrations/all/ebay - -e-conomic: - display_name: e-conomic - categories: - - accounting - auth_mode: BASIC - proxy: - base_url: https://restapi.e-conomic.com - headers: - content-type: application/json - docs: https://docs.nango.dev/integrations/all/e-conomic - -egnyte: - display_name: Egnyte - categories: - - storage - auth_mode: OAUTH2 - authorization_url: https://${connectionConfig.subdomain}.egnyte.com/puboauth/token - token_url: https://${connectionConfig.subdomain}.egnyte.com/puboauth/token - scope_separator: ' ' - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://${connectionConfig.subdomain}.egnyte.com/pubapi - docs: https://docs.nango.dev/integrations/all/egnyte - connection_config: - subdomain: - type: string - title: Egnyte Domain - description: The subdomain of your Egnyte account - pattern: '^[a-z0-9_-]+$' - example: domain - suffix: .egnyte.com - prefix: https:// - -elevenlabs: - display_name: Eleven Labs - categories: - - dev-tools - auth_mode: API_KEY - proxy: - base_url: https://api.elevenlabs.io - headers: - xi-api-key: ${apiKey} - verification: - method: GET - endpoint: /v1/user - docs: https://docs.nango.dev/integrations/all/elevenlabs - credentials: - apiKey: - type: string - title: API Key - description: The API key for your ElevenLabs account - -elevio: - display_name: Elevio - categories: - - knowledge-base - - support - auth_mode: API_KEY - proxy: - base_url: https://api.elev.io - headers: - x-api-key: ${apiKey} - authorization: Bearer ${connectionConfig.jwt} - docs: https://docs.nango.dev/integrations/all/elevio - credentials: - apiKey: - type: string - title: API Key - description: The API key to your Elevio account - pattern: '\b[a-f0-9]{40}\b' - example: 'x12z67890dd34t8gq5j01ycc75912348' - connection_config: - jwt: - type: string - title: JWT - description: The JWT to your Elevio account - pattern: '^[A-Za-z0-9-_]+\.([A-Za-z0-9-_]+\.[A-Za-z0-9-_]+)$' - -entrata: - display_name: Entrata - categories: - - other - auth_mode: BASIC - proxy: - base_url: https://${connectionConfig.subdomain}.entrata.com - docs: https://docs.nango.dev/integrations/all/entrata - connection_config: - subdomain: - type: string - title: Entrata Domain - description: The subdomain of your Entrata account - pattern: '^[a-z0-9_-]+$' - example: domain - suffix: .entrata.com - prefix: https:// - -envoy: - display_name: Envoy - categories: - - productivity - auth_mode: OAUTH2 - authorization_url: https://app.envoy.com/a/auth/v0/authorize - token_url: https://app.envoy.com/a/auth/v0/token - scope_separator: ' ' - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://api.envoy.com - docs: https://docs.nango.dev/integrations/all/envoy - -epic-games: - display_name: Epic Games - categories: - - gaming - auth_mode: OAUTH2 - authorization_url: https://www.epicgames.com/id/authorize - token_url: https://api.epicgames.dev/epic/oauth/v1/token - authorization_method: header - proxy: - base_url: https://api.epicgames.dev - docs: https://docs.nango.dev/integrations/all/epic-games - -evaluagent: - display_name: EvaluAgent - auth_mode: BASIC - proxy: - base_url: https://${connectionConfig.region}.evaluagent.com - verification: - method: GET - endpoint: /v1/ping - docs: https://docs.nango.dev/integrations/all/evaluagent - connection_config: - region: - type: string - title: Region - description: The region of your EvaluAgent account - example: eu - pattern: '^[a-z]+$' - -eventbrite: - display_name: Eventbrite - categories: - - marketing - auth_mode: OAUTH2 - authorization_url: https://www.eventbrite.com/oauth/authorize - token_url: https://www.eventbrite.com/oauth/token - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - proxy: - base_url: https://www.eventbriteapi.com - docs: https://docs.nango.dev/integrations/all/eventbrite - -exa: - display_name: Exa - categories: - - analytics - auth_mode: API_KEY - proxy: - base_url: https://api.exa.ai - headers: - x-api-key: ${apiKey} - docs: https://docs.nango.dev/integrations/all/exa - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Exa account - -exact-online: - display_name: Exact Online - categories: - - accounting - - hr - - productivity - auth_mode: OAUTH2 - authorization_url: https://start.exactonline.${connectionConfig.extension}/api/oauth2/auth - token_url: https://start.exactonline.${connectionConfig.extension}/api/oauth2/token - authorization_method: header - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - token_expiration_buffer: 30 - proxy: - base_url: https://start.exactonline.${connectionConfig.extension}/ - headers: - accept: application/json - retry: - at: 'x-ratelimit-reset' - paginate: - type: link - link_path_in_response_body: d.__next - docs: https://docs.nango.dev/integrations/all/exact-online - connection_config: - extension: - type: string - title: Domain Extension - description: The domain extension of your Exact Online account - example: nl - pattern: '^[a-z.]+$' - -exist: - display_name: Exist - categories: - - other - auth_mode: OAUTH2 - authorization_url: https://exist.io/oauth2/authorize - token_url: https://exist.io/oauth2/access_token - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://exist.io/ - paginate: - type: link - link_path_in_response_body: next - docs: https://docs.nango.dev/integrations/all/exist - -expensify: - display_name: Expensify - categories: - - productivity - auth_mode: BASIC - proxy: - base_url: https://integrations.expensify.com/Integration-Server/ - headers: - content-type: application/x-www-form-urlencoded - credentials: - username: - type: string - title: Partner User ID - description: Your unique account identifier of Expensify - doc_section: '#step-1-finding-your-partneruserid-and-partnerusersecret' - password: - type: string - title: Partner User Secret - description: Unique secret for your account - doc_section: '#step-1-finding-your-partneruserid-and-partnerusersecret' - docs: https://docs.nango.dev/integrations/all/expensify - docs_connect: https://docs.nango.dev/integrations/all/expensify/connect - -factorial: - display_name: Factorial - categories: - - hr - auth_mode: OAUTH2 - authorization_url: https://api.factorialhr.com/oauth/authorize - token_url: https://api.factorialhr.com/oauth/token - disable_pkce: true - proxy: - base_url: https://api.factorialhr.com/api - docs: https://docs.nango.dev/integrations/all/factorial - -facebook: - display_name: Facebook - categories: - - marketing - - social - auth_mode: OAUTH2 - authorization_url: https://www.facebook.com/v15.0/dialog/oauth - token_url: https://graph.facebook.com/v15.0/oauth/access_token - proxy: - base_url: https://graph.facebook.com - docs: https://docs.nango.dev/integrations/all/facebook - -figjam: - display_name: FigJam - categories: - - design - - productivity - alias: figma - docs: https://docs.nango.dev/integrations/all/figjam - -figma: - display_name: Figma - categories: - - design - - productivity - auth_mode: OAUTH2 - authorization_url: https://www.figma.com/oauth - token_url: https://www.figma.com/api/oauth/token - refresh_url: https://www.figma.com/api/oauth/refresh - disable_pkce: true - proxy: - base_url: https://api.figma.com - docs: https://docs.nango.dev/integrations/all/figma - -falai: - display_name: fal.ai - categories: - - productivity - - dev-tools - auth_mode: API_KEY - proxy: - headers: - authorization: Key ${apiKey} - base_url: https://queue.fal.run - docs: https://docs.nango.dev/integrations/all/falai - credentials: - apiKey: - type: string - title: API Key - description: The API key for your fal.ai account - -findymail: - display_name: FindyMail - categories: - - marketing - - crm - auth_mode: API_KEY - proxy: - base_url: https://app.findymail.com - headers: - authorization: Bearer ${apiKey} - docs: https://docs.nango.dev/integrations/all/findymail - docs_connect: https://docs.nango.dev/integrations/all/findymail/connect - credentials: - apiKey: - type: string - title: API Key - description: The API key for your FindyMail account - -firefish: - display_name: Firefish - scope_separator: ' ' - categories: - - crm - auth_mode: OAUTH2_CC - token_url: https://api.firefishsoftware.com/authorization/token - token_params: - grant_type: client_credentials - proxy: - base_url: https://api.firefishsoftware.com - docs: https://docs.nango.dev/integrations/all/firefish - -fireflies: - display_name: Fireflies - categories: - - analytics - - communication - - productivity - auth_mode: API_KEY - proxy: - base_url: https://api.fireflies.ai - headers: - authorization: Bearer ${apiKey} - docs: https://docs.nango.dev/integrations/all/fireflies - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Fireflies account - -fiserv: - display_name: Fiserv - categories: - - banking - - payment - auth_mode: OAUTH2_CC - token_url: https://cert.api.fiservapps.com/fts-apim/oauth2/v2 - token_request_auth_method: basic - expires_in_unit: milliseconds - token_params: - grant_type: client_credentials - proxy: - base_url: https://${connectionConfig.hostUrl} - docs: https://docs.nango.dev/integrations/all/fiserv - connection_config: - hostUrl: - type: string - title: Domain - description: The domain of your Fiserv account - format: hostname - prefix: https:// - -fiserv-api-key: - display_name: Fiserv (api key) - categories: - - banking - - payment - auth_mode: API_KEY - proxy: - base_url: https://prod.emea.api.fiservapps.com - headers: - api-key: ${apiKey} - verification: - method: GET - endpoint: /sandbox/exp/v1/authorisations - docs: https://docs.nango.dev/integrations/all/fiserv - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Fiserv account - -fitbit: - display_name: Fitbit - categories: - - sports - auth_mode: OAUTH2 - authorization_url: https://www.fitbit.com/oauth2/authorize - token_url: https://api.fitbit.com/oauth2/token - authorization_method: header - proxy: - base_url: https://api.fitbit.com - docs: https://docs.nango.dev/integrations/all/fitbit - -fortnox: - display_name: Fortnox - categories: - - accounting - - invoicing - auth_mode: OAUTH2 - authorization_url: https://apps.fortnox.se/oauth-v1/auth - token_url: https://apps.fortnox.se/oauth-v1/token - token_request_auth_method: basic - scope_separator: ' ' - authorization_params: - response_type: code - access_type: offline - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://api.fortnox.se/3 - docs: https://docs.nango.dev/integrations/all/fortnox - -freshbooks: - display_name: FreshBooks - categories: - - accounting - auth_mode: OAUTH2 - authorization_url: https://auth.freshbooks.com/oauth/authorize - token_url: https://api.freshbooks.com/auth/oauth/token - authorization_params: - response_type: code - proxy: - base_url: https://api.freshbooks.com - docs: https://docs.nango.dev/integrations/all/freshbooks - -freshdesk: - display_name: FreshDesk - categories: - - support - auth_mode: BASIC - proxy: - base_url: https://${connectionConfig.subdomain}.freshdesk.com - verification: - endpoint: /api/v2/settings/helpdesk - docs: https://docs.nango.dev/integrations/all/freshdesk - docs_connect: https://docs.nango.dev/integrations/all/freshdesk/connect - credentials: - username: - type: string - title: FreshDesk API Key - description: The API Key of your FreshDesk account - doc_section: '#step-1-finding-your-freshdesk-api-key' - secret: true - password: - type: string - title: '' - description: '' - default_value: X - hidden: true - connection_config: - subdomain: - type: string - title: FreshDesk Domain - description: The subdomain of your FreshDesk account - pattern: '^[a-z0-9_-]+$' - example: domain - suffix: .freshdesk.com - prefix: https:// - doc_section: '#step-2-finding-your-freshdesk-domain' - -freshsales: - display_name: Freshsales - categories: - - crm - auth_mode: API_KEY - proxy: - base_url: https://${connectionConfig.subdomain}.freshsales.io - verification: - method: GET - endpoint: /api/settings/leads/fields - headers: - authorization: Token token=${apiKey} - retry: - after: 'retry-after' - docs: https://docs.nango.dev/integrations/all/freshsales - docs_connect: https://docs.nango.dev/integrations/all/freshsales/connect - connection_config: - subdomain: - type: string - title: Freshsales subdomain - description: The subdomain of your Freshsales account - pattern: '^[a-z0-9_-]+$' - example: subdomain - suffix: .freshsales.io - prefix: https:// - doc_section: '#step-2-finding-your-freshsales-subdomain' - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Freshsales account - example: 4oBqA_AzM_G3xbW3TJGvrA - pattern: '[A-Za-z0-9_]{22}' - doc_section: '#step-1-finding-your-freshsales-api-key' - -freshservice: - display_name: Freshservice - categories: - - support - auth_mode: BASIC - proxy: - base_url: https://${connectionConfig.subdomain}.freshservice.com - verification: - method: GET - endpoint: /api/v2/tickets - retry: - after: 'retry-after' - docs: https://docs.nango.dev/integrations/all/freshservice - docs_connect: https://docs.nango.dev/integrations/all/freshservice/connect - connection_config: - subdomain: - type: string - title: Freshservice subdomain - description: The subdomain of your Freshservice account - pattern: '^[a-z0-9_-]+$' - example: subdomain - suffix: .freshservice.com - prefix: https:// - doc_section: '#step-2-finding-your-freshservice-subdomain' - credentials: - username: - type: string - title: API key - description: The API Key of your Freshservice account - secret: true - doc_section: '#step-1-finding-your-freshservice-api-key' - password: - type: string - title: '' - description: '' - # https://api.freshservice.com/#authentication - # FreshService is using basic auth with an api key, the basic username/password was deprecated - default_value: 'X' - hidden: true - -freshteam: - display_name: Freshteam - categories: - - hr - auth_mode: API_KEY - proxy: - base_url: https://${connectionConfig.accountName}.freshteam.com - headers: - authorization: Bearer ${apiKey} - accept: application/json - docs: https://docs.nango.dev/integrations/all/freshteam - docs_connect: https://docs.nango.dev/integrations/all/freshteam/connect - connection_config: - accountName: - type: string - title: Account Name - description: The account name of your Freshteam account - example: nango - format: hostname - suffix: .freshteam.com - prefix: https:// - order: 1 - doc_section: '#step-1-finding-your-account-name' - credentials: - apiKey: - type: string - title: API Key - description: The API key to your Freshteam account - doc_section: '#step-2-finding-your-api-key' - example: 'XtoF94LMNyKPbd5AvR1QJh' - pattern: '^[a-zA-Z0-9_!@#$%^&*()\\-+=]+$' - -front: - display_name: Front - categories: - - support - - ticketing - auth_mode: OAUTH2 - authorization_url: https://app.frontapp.com/oauth/authorize - token_url: https://app.frontapp.com/oauth/token - proxy: - base_url: https://api2.frontapp.com - retry: - after: 'retry-after' - paginate: - type: link - response_path: _results - link_path_in_response_body: _pagination.next - docs: https://docs.nango.dev/integrations/all/front - -gainsight-cc: - display_name: Gainsight CC - categories: - - support - - crm - auth_mode: OAUTH2_CC - token_url: https://api2-${connectionConfig.region}.insided.com/oauth2/token - scope_separator: ' ' - token_params: - grant_type: client_credentials - proxy: - base_url: https://api2-${connectionConfig.region}.insided.com - docs: https://docs.nango.dev/integrations/all/gainsight-cc - docs_connect: https://docs.nango.dev/integrations/all/gainsight-cc/connect - connection_config: - region: - type: string - title: Region - description: The region of your Gainsight account - example: eu-west-1 - pattern: '^[a-z]{2}-[a-z]+-[1-9]$' - doc_section: '#step-2-finding-your-region' - -garmin: - display_name: Garmin - categories: - - sports - auth_mode: OAUTH1 - request_url: https://connectapi.garmin.com/oauth-service/oauth/request_token - authorization_url: https://connect.garmin.com/oauthConfirm - token_url: https://connectapi.garmin.com/oauth-service/oauth/access_token - signature_method: 'HMAC-SHA1' - proxy: - base_url: https://apis.garmin.com - docs: https://docs.nango.dev/integrations/all/garmin - -gerrit: - display_name: Gerrit - categories: - - dev-tools - auth_mode: BASIC - proxy: - base_url: https://${connectionConfig.host} - verification: - method: GET - endpoint: /config/server/version - docs: https://docs.nango.dev/integrations/all/gerrit - docs_connect: https://docs.nango.dev/integrations/all/gerrit/connect - connection_config: - host: - type: string - title: Gerrit Host - description: The host to where you Gerrit instance is hosted - pattern: '^https?:\/\/[a-z0-9.-]+(:\d+)?(\/.*)?$' - example: http://localhost:8080 - doc_section: '#step-1-finding-your-host' - order: 1 - -guru: - display_name: Guru - categories: - - knowledge-base - auth_mode: BASIC - proxy: - base_url: https://api.getguru.com/api/v1 - verification: - method: GET - endpoint: /whoami - docs: https://docs.nango.dev/integrations/all/guru - docs_connect: https://docs.nango.dev/integrations/all/guru/connect - credentials: - username: - type: string - title: User/Collection ID - description: The user or collection ID of your Guru account - doc_section: '#step-1-finding-your-user-collection-id' - password: - type: string - title: User/Collection Token - description: The user or collection token of your Guru account - secret: true - format: uuid - example: 123e4567-e89b-12d3-a456-426614174000 - doc_section: '#step-2-generating-your-user-collection-token' - -github: - display_name: GitHub - categories: - - dev-tools - - support - - ticketing - auth_mode: OAUTH2 - authorization_url: https://github.com/login/oauth/authorize - token_url: https://github.com/login/oauth/access_token - proxy: - base_url: https://api.github.com - retry: - at: 'x-ratelimit-reset' - remaining: 'x-ratelimit-remaining' - error_code: 403 - paginate: - type: link - limit_name_in_request: per_page - link_rel_in_response_header: next - docs: https://docs.nango.dev/integrations/all/github - -github-app: - display_name: GitHub App - categories: - - dev-tools - - ticketing - alias: github - auth_mode: APP - authorization_url: ${connectionConfig.appPublicLink}/installations/new - token_url: https://api.github.com/app/installations/${connectionConfig.installation_id}/access_tokens - webhook_routing_script: githubAppWebhookRouting - docs: https://docs.nango.dev/integrations/all/github - connection_config: - appPublicLink: - type: string - title: App Public Link - description: The public link of your GitHub App - format: uri - pattern: '^https?://.*$' - installation_id: - type: string - title: Installation ID - description: The installation ID of your GitHub App - example: '38631545' - automated: true - -github-app-oauth: - display_name: GitHub App (oauth) - categories: - - dev-tools - - ticketing - alias: github - auth_mode: CUSTOM - authorization_url: ${connectionConfig.appPublicLink}/installations/new - authorization_url_skip_encode: - - base_url - token_url: - OAUTH2: https://github.com/login/oauth/access_token - APP: https://api.github.com/app/installations/${connectionConfig.installation_id}/access_tokens - webhook_routing_script: githubAppOauthWebhookRouting - post_connection_script: githubAppOauthPostConnection - docs: https://docs.nango.dev/integrations/all/github - connection_config: - appPublicLink: - type: string - title: App Public Link - description: The public link of your GitHub App - format: uri - pattern: '^https?://.*$' - installation_id: - type: string - title: Installation ID - description: The installation ID of your GitHub App - example: '38631545' - automated: true - -gitlab: - display_name: GitLab - categories: - - dev-tools - - ticketing - auth_mode: OAUTH2 - authorization_url: https://gitlab.com/oauth/authorize - token_url: https://gitlab.com/oauth/token - authorization_params: - response_type: code - proxy: - base_url: https://gitlab.com - docs: https://docs.nango.dev/integrations/all/gitlab - -ghost-admin: - display_name: Ghost (Admin API) - categories: - - dev-tools - - design - - cms - auth_mode: JWT - token: - expires_in_ms: 300000 - headers: - alg: HS256 - payload: - aud: /admin/ - proxy: - headers: - accept: application/json - accept-version: ${connectionConfig.version} - base_url: https://${connectionConfig.adminDomain}/ghost/api/admin/ - docs: https://docs.nango.dev/integrations/all/ghost - connection_config: - adminDomain: - type: string - title: Ghost Admin Domain - description: The domain of your Ghost Admin which can be different from your main domain - example: 'mock.ghost.io' - pattern: '^([a-z0-9_-]+\.|)(ghost\.io|[a-z0-9_-]+\.[a-z]{2,})$' - version: - type: string - title: API Version - description: The version of the Ghost Admin API to use - example: 'v3.0' - pattern: '^v\d+\.\d+$' - -ghost-content: - display_name: Ghost (Content API) - categories: - - dev-tools - - design - - cms - auth_mode: API_KEY - proxy: - headers: - accept-version: ${connectionConfig.version} - base_url: https://${connectionConfig.adminDomain}/ghost/api/content/ - query: - key: ${apiKey} - verification: - method: GET - endpoint: /tags - docs: https://docs.nango.dev/integrations/all/ghost - connection_config: - version: - type: string - title: API Version - description: The version of the Ghost Admin API to use - example: 'v3.0' - pattern: '^v\d+\.\d+$' - adminDomain: - type: string - title: Ghost Admin Domain - description: The domain of your Ghost Admin which can be different from your main domain - example: 'mock.ghost.io' - pattern: '^([a-z0-9_-]+\.|)(ghost\.io|[a-z0-9_-]+\.[a-z]{2,})$' - credentials: - apiKey: - type: string - title: API Key - description: The content API key for your Ghost account - pattern: '^[a-zA-Z0-9]{26}$' - example: a1b2c3d4e5f6g7h8i9j0k1l2m3 - -gong: - display_name: Gong - categories: - - productivity - auth_mode: BASIC - proxy: - base_url: https://api.gong.io - retry: - after: 'retry-after' - docs: https://docs.nango.dev/integrations/all/gong - docs_connect: https://docs.nango.dev/integrations/all/gong/connect - credentials: - username: - type: string - title: Access Key - description: Your Gong Access Key - pattern: '^[a-zA-Z0-9-]+$' - doc_section: '#step-1-finding-gong-api-key-and-api-key-secret' - password: - type: string - title: Access Key Secret - description: Your Gong Access Key Secret - default_value: '' - doc_section: '#step-1-finding-gong-api-key-and-api-key-secret' - -gong-oauth: - display_name: Gong (oauth) - auth_mode: OAUTH2 - categories: - - productivity - authorization_url: https://app.gong.io/oauth2/authorize - token_url: https://app.gong.io/oauth2/generate-customer-token - token_response_metadata: - - api_base_url_for_customer - authorization_params: - response_type: code - access_type: offline - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - disable_pkce: true - token_request_auth_method: basic - proxy: - base_url: ${connectionConfig.api_base_url_for_customer} || https://api.gong.io - retry: - after: 'retry-after' - docs: https://docs.nango.dev/integrations/all/gong - connection_config: - api_base_url_for_customer: - type: string - title: API Base URL - description: The base URL of your Gong account - format: uri - pattern: '^https?://.*$' - -google: - display_name: Google - auth_mode: OAUTH2 - authorization_url: https://accounts.google.com/o/oauth2/v2/auth - token_url: https://oauth2.googleapis.com/token - authorization_params: - response_type: code - access_type: offline - prompt: consent - proxy: - base_url: https://www.googleapis.com - paginate: - type: cursor - cursor_path_in_response: nextPageToken - limit_name_in_request: maxSize - cursor_name_in_request: pageToken - response_path: items - docs: https://docs.nango.dev/integrations/all/google - -google-analytics: - display_name: Google Analytics - alias: google - categories: - - analytics - docs: https://docs.nango.dev/integrations/all/google-analytics - -google-calendar: - display_name: Google Calendar - categories: - - productivity - alias: google - proxy: - base_url: https://www.googleapis.com - paginate: - type: cursor - cursor_path_in_response: nextPageToken - limit_name_in_request: maxSize - cursor_name_in_request: pageToken - response_path: items - docs: https://docs.nango.dev/integrations/all/google-calendar - -google-docs: - display_name: Google Docs - categories: - - productivity - alias: google - proxy: - base_url: https://docs.googleapis.com - docs: https://docs.nango.dev/integrations/all/google-docs - -google-mail: - display_name: Google Mail - categories: - - productivity - alias: google - proxy: - base_url: https://gmail.googleapis.com - docs: https://docs.nango.dev/integrations/all/google-mail - -google-sheet: - display_name: Google Sheet - categories: - - productivity - alias: google - proxy: - base_url: https://sheets.googleapis.com - docs: https://docs.nango.dev/integrations/all/google-sheet - -google-drive: - display_name: Google Drive - categories: - - knowledge-base - - storage - alias: google - docs: https://docs.nango.dev/integrations/all/google-drive - -google-ads: - display_name: Google Ads - categories: - - marketing - alias: google - token_url: https://www.googleapis.com/oauth2/v3/token - proxy: - base_url: https://googleads.googleapis.com - paginate: - type: cursor - cursor_path_in_response: nextPageToken - limit_name_in_request: pageSize - cursor_name_in_request: pageToken - response_path: results - docs: https://docs.nango.dev/integrations/all/google-ads - -google-play: - display_name: Google Play - categories: - - dev-tools - auth_mode: OAUTH2 - authorization_url: https://accounts.google.com/o/oauth2/auth - token_url: https://accounts.google.com/o/oauth2/token - authorization_params: - response_type: code - access_type: offline - prompt: consent - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://play.googleapis.com - docs: https://docs.nango.dev/integrations/all/google-play - -gorgias: - display_name: Gorgias - categories: - - e-commerce - auth_mode: OAUTH2 - authorization_url: https://${connectionConfig.subdomain}.gorgias.com/oauth/authorize - token_url: https://${connectionConfig.subdomain}.gorgias.com/oauth/token - token_request_auth_method: basic - default_scopes: - - offline - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://${connectionConfig.subdomain}.gorgias.com - retry: - after: 'retry-after' - docs: https://docs.nango.dev/integrations/all/gorgias - connection_config: - subdomain: - type: string - title: Gorgias Domain - description: The subdomain of your Gorgias account - pattern: '^[a-z0-9_-]+$' - example: domain - suffix: .gorgias.com - prefix: https:// - -grain: - display_name: Grain - categories: - - video - - communication - - productivity - auth_mode: OAUTH2 - authorization_url: https://grain.com/_/public-api/oauth2/authorize - token_url: https://api.grain.com/_/public-api/oauth2/token - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - proxy: - base_url: https://api.grain.com - docs: https://docs.nango.dev/integrations/all/grain - -grain-api-key: - display_name: Grain (api key) - categories: - - video - - communication - - productivity - auth_mode: API_KEY - proxy: - base_url: https://api.grain.com - verification: - method: GET - endpoint: /_/public-api/me - headers: - authorization: Bearer ${apiKey} - docs: https://docs.nango.dev/integrations/all/grain - credentials: - apiKey: - type: string - title: API Key - description: The personal access token to your Grain account - -greenhouse: - display_name: Greenhouse - categories: - - ats - auth_mode: OAUTH2 - authorization_url: https://api.greenhouse.io/oauth/authorize - token_url: https://api.greenhouse.io/oauth/token - proxy: - base_url: https://${connectionConfig.resource}.greenhouse.io - retry: - after: 'retry-after' - paginate: - type: link - limit_name_in_request: per_page - link_rel_in_response_header: next - docs: https://docs.nango.dev/integrations/all/greenhouse - connection_config: - resource: - type: string - title: Greenhouse API Domain - description: The Greenhouse API Domain you want to connect to - pattern: '^[a-z0-9_-]+$' - example: harvest - suffix: .greenhouse.io - prefix: https:// - -greenhouse-basic: - display_name: Greenhouse (basic auth) - categories: - - ats - auth_mode: BASIC - proxy: - base_url: https://${connectionConfig.resource}.greenhouse.io - retry: - after: 'retry-after' - paginate: - type: link - limit_name_in_request: per_page - link_rel_in_response_header: next - docs: https://docs.nango.dev/integrations/all/greenhouse - docs_connect: https://docs.nango.dev/integrations/all/greenhouse-basic/connect - connection_config: - resource: - type: string - title: Greenhouse API Domain - description: The Greenhouse API Domain you want to connect to - pattern: '^[a-z0-9_-]+$' - example: harvest - suffix: .greenhouse.io - prefix: https:// - order: 1 - credentials: - username: - type: string - title: API key - description: The API Key of your Greenhouse account - pattern: '^[a-zA-Z0-9-]+$' - secret: true - doc_section: '#step-1-finding-greenhouse-api-key' - password: - type: string - title: Password - description: Password - # https://developers.greenhouse.io/harvest.html#authentication - # Greenhouse is using basic auth with an api key - default_value: '' - hidden: true - -gumroad: - display_name: Gumroad - categories: - - design - - e-commerce - - payment - auth_mode: OAUTH2 - authorization_url: https://gumroad.com/oauth/authorize - token_url: https://api.gumroad.com/oauth/token - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://api.gumroad.com - docs: https://docs.nango.dev/integrations/all/gumroad - -gusto: - display_name: Gusto - categories: - - hr - auth_mode: OAUTH2 - authorization_url: https://api.gusto.com/oauth/authorize - token_url: https://api.gusto.com/oauth/token - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://api.gusto.com - post_connection_script: gustoPostConnection - docs: https://docs.nango.dev/integrations/all/gusto - -gusto-demo: - display_name: Gusto (demo) - auth_mode: OAUTH2 - authorization_url: https://api.gusto-demo.com/oauth/authorize - token_url: https://api.gusto-demo.com/oauth/token - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://api.gusto-demo.com - post_connection_script: gustoPostConnection - docs: https://docs.nango.dev/integrations/all/gusto - -hackerrank-work: - display_name: HackerRank Work - auth_mode: BASIC - proxy: - base_url: https://www.hackerrank.com - verification: - method: GET - endpoint: /x/api/v3/users?limit=10&offset=10 - docs: https://docs.nango.dev/integrations/all/hackerrank-work - docs_connect: https://docs.nango.dev/integrations/all/hackerrank-work/connect - credentials: - username: - type: string - title: API Key - description: Your HackerRank Work API Key - doc_section: '#step-1-finding-hackerrank-api-key' - password: - type: string - title: '' - description: '' - default_value: '' - hidden: true - -harvest: - display_name: Harvest - categories: - - productivity - auth_mode: OAUTH2 - authorization_url: https://id.getharvest.com/oauth2/authorize - token_url: https://id.getharvest.com/api/v2/oauth2/token - scope_separator: ' ' - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - headers: - user-agent: ${connectionConfig.appDetails} || App (support@nango.dev) - retry: - after: 'retry-after' - base_url: https://api.harvestapp.com - docs: https://docs.nango.dev/integrations/all/harvest - connection_config: - appDetails: - type: string - title: App Details - description: The details of your app - automated: true - -health-gorilla: - display_name: Health Gorilla - auth_mode: OAUTH2 - authorization_url: https://api.healthgorilla.com/oauth/authorize - token_url: https://api.healthgorilla.com/oauth/token - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://healthgorilla.com - docs: https://docs.nango.dev/integrations/all/healthgorilla - -hibob-service-user: - display_name: Hibob Service User - categories: - - hr - auth_mode: BASIC - proxy: - base_url: https://api.hibob.com - verification: - method: GET - endpoint: /v1/company/named-lists - retry: - at: 'x-ratelimit-reset' - credentials: - username: - type: string - title: User name - description: Your Hibob ID - doc_section: '#step-1-finding-your-hibob-service-user-id' - password: - type: string - title: Password - description: Your Hibob Token - default_value: '' - hidden: true - doc_section: '#step-2-finding-your-hibob-token' - docs: https://docs.nango.dev/integrations/all/hibob - docs_connect: https://docs.nango.dev/integrations/all/hibob-service-user/connect - -highlevel: - display_name: HighLevel - categories: - - marketing - auth_mode: OAUTH2 - authorization_url: https://marketplace.gohighlevel.com/oauth/chooselocation - token_url: https://services.leadconnectorhq.com/oauth/token - scope_separator: ' ' - proxy: - base_url: https://services.leadconnectorhq.com - disable_pkce: true - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - docs: https://docs.nango.dev/integrations/all/highlevel - -highlevel-white-label: - display_name: HighLevel (white label) - categories: - - marketing - auth_mode: OAUTH2 - authorization_url: https://marketplace.leadconnectorhq.com/oauth/chooselocation - token_url: https://services.leadconnectorhq.com/oauth/token - scope_separator: ' ' - proxy: - base_url: https://services.leadconnectorhq.com - disable_pkce: true - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - docs: https://docs.nango.dev/integrations/all/highlevel - -holded: - display_name: Holded - categories: - - accounting - - crm - - invoicing - auth_mode: API_KEY - proxy: - base_url: https://api.holded.com/api - headers: - key: ${apiKey} - verification: - method: GET - endpoint: /invoicing/v1/contacts - docs: https://docs.nango.dev/integrations/all/holded - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Holded account - -hubspot: - display_name: HubSpot - categories: - - marketing - - support - - crm - auth_mode: OAUTH2 - authorization_url: https://app.hubspot.com/oauth/authorize - token_url: https://api.hubapi.com/oauth/v1/token - connection_configuration: - - portalId - post_connection_script: hubspotPostConnection - webhook_routing_script: hubspotWebhookRouting - proxy: - base_url: https://api.hubapi.com - decompress: true - paginate: - type: cursor - cursor_path_in_response: paging.next.after - limit_name_in_request: limit - cursor_name_in_request: after - response_path: results - docs: https://docs.nango.dev/integrations/all/hubspot - -insightly: - display_name: Insightly - categories: - - crm - auth_mode: BASIC - proxy: - base_url: https://api.${connectionConfig.pod}.insightly.com - verification: - method: GET - endpoint: /v3.1/Contacts - docs: https://docs.nango.dev/integrations/all/insightly - connection_config: - pod: - type: string - title: Insightly Domain - description: The subdomain of your Insightly account - pattern: '^[a-z0-9_-]+$' - example: domain - suffix: .insightly.com - prefix: https:// - credentials: - username: - type: string - title: API Key - description: Your Insightly API key - password: - type: string - title: '' - description: '' - hidden: true - default_value: '' - -instantly: - display_name: Instantly - categories: - - marketing - - communication - auth_mode: API_KEY - proxy: - base_url: https://api.instantly.ai/api - docs: https://docs.nango.dev/integrations/all/instantly - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Instantly account - -instagram: - display_name: Instagram - categories: - - marketing - - social - auth_mode: OAUTH2 - authorization_url: https://api.instagram.com/oauth/authorize - token_url: https://api.instagram.com/oauth/access_token - proxy: - base_url: https://graph.instagram.com - docs: https://docs.nango.dev/integrations/all/instagram - -intercom: - display_name: Intercom - categories: - - marketing - - support - - surveys - - ticketing - auth_mode: OAUTH2 - authorization_url: https://app.intercom.io/oauth - token_url: https://api.intercom.io/auth/eagle/token - proxy: - base_url: https://api.intercom.io - retry: - at: 'x-ratelimit-reset' - docs: https://docs.nango.dev/integrations/all/intercom - -intuit: - display_name: Intuit - categories: - - accounting - auth_mode: OAUTH2 - authorization_url: https://appcenter.intuit.com/connect/oauth2 - token_url: https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer - proxy: - base_url: https://quickbooks.api.intuit.com - docs: https://docs.nango.dev/integrations/all/intuit - -jira: - display_name: Jira - categories: - - productivity - - ticketing - auth_mode: OAUTH2 - authorization_url: https://auth.atlassian.com/authorize - token_url: https://auth.atlassian.com/oauth/token - authorization_params: - audience: api.atlassian.com - prompt: consent - connection_configuration: - - cloudId - - accountId - proxy: - base_url: https://api.atlassian.com - paginate: - type: link - link_rel_in_response_header: next - limit_name_in_request: limit - response_path: results - link_path_in_response_body: _links.next - post_connection_script: jiraPostConnection - webhook_routing_script: jiraWebhookRouting - docs: https://docs.nango.dev/integrations/all/jira - -jira-basic: - display_name: Jira (basic auth) - categories: - - productivity - - ticketing - auth_mode: BASIC - proxy: - retry: - after: 'retry-after' - base_url: https://${connectionConfig.subdomain}.atlassian.net - verification: - method: GET - endpoint: /rest/api/3/events - docs: https://docs.nango.dev/integrations/all/jira - connection_config: - subdomain: - type: string - title: Jira Domain - description: The subdomain of your Jira account - pattern: '^[a-z0-9_-]+$' - example: domain - suffix: .atlassian.net - prefix: https:// - order: 1 - doc_section: '#step-2-finding-your-atlassian-domain' - credentials: - username: - type: string - title: Email Address - description: The Email Address of your Jira account - format: email - doc_section: '#step-3-finding-your-user-name' - password: - type: string - title: API Key - description: The API Key of your Jira account - doc_section: '#step-1-finding-atlassian-api-key' - docs_connect: https://docs.nango.dev/integrations/all/jira-basic/connect - -jira-data-center: - display_name: Jira Data Center - categories: - - productivity - - ticketing - auth_mode: OAUTH2 - authorization_url: https://${connectionConfig.endpointURL}/rest/oauth2/latest/authorize - authorization_params: - grant_type: authorization_code - token_url: https://${connectionConfig.endpointURL}/rest/oauth2/latest/token - docs: https://docs.nango.dev/integrations/all/jira-data-center - proxy: - base_url: https://${connectionConfig.endpointURL}/rest/api/latest - connection_config: - endpointURL: - type: string - title: Domain - description: The domain of your Jira Data Center account - pattern: '^https://[a-z0-9.-]+.atlassian.net$' - example: https://foobar.atlassian.net - -jotform: - display_name: Jotform - categories: - - surveys - auth_mode: API_KEY - proxy: - base_url: https://api.jotform.com - headers: - apikey: ${apiKey} - docs: https://docs.nango.dev/integrations/all/jotform - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Jotform account - -helpscout-docs: - display_name: Help Scout Docs - auth_mode: BASIC - proxy: - retry: - after: 'x-ratelimit-reset' - base_url: https://docsapi.helpscout.net - verification: - method: GET - endpoint: /v1/sites - docs: https://docs.nango.dev/integrations/all/helpscout - docs_connect: https://docs.nango.dev/integrations/all/helpscout-docs/connect - credentials: - username: - type: string - title: API Key - description: Your Help Scout Docs API Key - secret: true - doc_section: '#step-1-finding-help-scout-api-key' - password: - type: string - title: '' - description: '' - default_value: 'X' - hidden: true - -helpscout-mailbox: - display_name: Help Scout Mailbox - auth_mode: OAUTH2 - authorization_url: https://secure.helpscout.net/authentication/authorizeClientApplication - token_url: https://api.helpscout.net/v2/oauth2/token - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - retry: - after: 'x-ratelimit-retry-after' - base_url: https://api.helpscout.net - docs: https://docs.nango.dev/integrations/all/helpscout - -keap: - display_name: Keap - categories: - - marketing - auth_mode: OAUTH2 - authorization_url: https://accounts.infusionsoft.com/app/oauth/authorize - token_url: https://api.infusionsoft.com/token - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://api.infusionsoft.com - docs: https://docs.nango.dev/integrations/all/keap - -keeper-scim: - display_name: Keeper(SCIM) - categories: - - productivity - auth_mode: API_KEY - proxy: - headers: - authorization: Bearer ${apiKey} - base_url: https://keepersecurity.com/api/rest/scim/v2/${connectionConfig.node} - verification: - method: GET - endpoint: /Users - docs: https://docs.nango.dev/integrations/all/keeper - docs_connect: https://docs.nango.dev/integrations/all/keeper/connect - credentials: - apiKey: - type: string - title: API Key - description: The API key for your node keeper account - pattern: '^[A-Za-z0-9+/=]+$' - example: 'J9b7kgdL2gf14d5F9p67zYXVrTZPTMEnl3/EmwwI9K2=' - doc_section: '#step-2-finding-your-api-key-api-token' - connection_config: - node: - type: string - title: Node - description: The node id to your Keeper account - pattern: '^\d{15}$' - example: '123435384338765' - doc_section: '#step-1-finding-your-node-id' - -klipfolio: - display_name: Klipfolio - categories: - - productivity - - dev-tools - auth_mode: API_KEY - proxy: - base_url: https://app.klipfolio.com - headers: - kf-api-key: ${apiKey} - verification: - method: GET - endpoint: /api/1.0/profile - docs: https://docs.nango.dev/integrations/all/klipfolio - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Klipfolio account - -klaviyo: - display_name: Klaviyo - categories: - - marketing - auth_mode: API_KEY - proxy: - base_url: https://a.klaviyo.com - headers: - authorization: Klaviyo-API-Key ${apiKey} - revision: '2024-07-15' - verification: - method: GET - endpoint: /api/accounts - retry: - after: 'retry-after' - docs: https://docs.nango.dev/integrations/all/klaviyo - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Klaviyo account - doc_section: '#step-1-finding-klaviyo-api-key' - -klaviyo-oauth: - display_name: Klaviyo (oauth) - categories: - - marketing - auth_mode: OAUTH2 - authorization_url: https://www.klaviyo.com/oauth/authorize - token_url: https://a.klaviyo.com/oauth/token - token_request_auth_method: basic - scope_separator: ' ' - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://a.klaviyo.com - headers: - revision: '2024-07-15' - retry: - after: 'retry-after' - docs: https://docs.nango.dev/integrations/all/klaviyo - -kustomer: - display_name: Kustomer - categories: - - crm - auth_mode: API_KEY - proxy: - base_url: https://${connectionConfig.extension}.kustomerapp.com - retry: - after: 'x-ratelimit-reset' - headers: - authorization: Bearer ${apiKey} - docs: https://docs.nango.dev/integrations/all/kustomer - connection_config: - extension: - type: string - title: Kustomer Domain - description: The subdomain of your Kustomer account - pattern: '^[a-z0-9_-]+$' - example: domain - suffix: .kustomerapp.com - prefix: https:// - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Kustomer account - -lagrowthmachine: - display_name: La Growth Machine - categories: - - marketing - auth_mode: API_KEY - proxy: - base_url: https://apiv2.lagrowthmachine.com - query: - KEY: ${apiKey} - docs: https://docs.nango.dev/integrations/all/lagrowthmachine - docs_connect: https://docs.nango.dev/integrations/all/lagrowthmachine/connect - credentials: - apiKey: - type: string - title: API Key - description: The API key for your La Growth Machine account - example: 1bc32cba-a5d6-438a-bbcc-af312f560a3c - format: uuid - doc_section: '#step-1-finding-your-api-key' - -lastpass: - display_name: LastPass - categories: - - productivity - auth_mode: BASIC - proxy: - base_url: https://lastpass.com - docs: https://docs.nango.dev/integrations/all/lastpass - docs_connect: https://docs.nango.dev/integrations/all/lastpass/connect - credentials: - username: - type: string - title: CID - description: Your LastPass Account number - doc_section: '#step-1-finding-your-cid' - password: - type: string - title: Provhash - description: 'Your LastPass API key' - secret: true - doc_section: '#step-2-generating-your-provhash' - -lattice: - display_name: Lattice - categories: - - hr - auth_mode: API_KEY - proxy: - base_url: https://api.latticehq.com/ - headers: - authorization: Bearer ${apiKey} - accept: application/json - content-type: application/json - retry: - after: 'retry-after' - docs: https://docs.nango.dev/integrations/all/lattice - docs_connect: https://docs.nango.dev/integrations/all/lattice/connect - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Lattice account - doc_section: '#step-1-finding-lattice-api-key' - -lessonly: - display_name: Lessonly - categories: - - productivity - auth_mode: BASIC - proxy: - base_url: https://api.lessonly.com/api - docs: https://docs.nango.dev/integrations/all/lessonly - credentials: - username: - type: string - title: Subdomain - description: Your Lessonly Subdomain - password: - type: string - title: API Key - description: Your Lessonly API key - secret: true - -lever: - display_name: Lever - categories: - - ats - auth_mode: OAUTH2 - authorization_url: https://auth.lever.co/authorize - token_url: https://auth.lever.co/oauth/token - authorization_params: - response_type: code - prompt: consent - audience: https://api.lever.co/v1 - proxy: - base_url: https://api.lever.co - docs: https://docs.nango.dev/integrations/all/lever - -lever-basic: - display_name: Lever (basic auth) - auth_mode: BASIC - proxy: - base_url: https://api.lever.co - docs: https://docs.nango.dev/integrations/all/lever - docs_connect: https://docs.nango.dev/integrations/all/lever-basic/connect - credentials: - username: - type: string - title: User name - description: The API Key of your lever account - doc_section: '#step-1-finding-lever-api-key' - password: - type: string - title: '' - description: '' - default_value: '' - hidden: true - -lever-sandbox: - display_name: Lever (sandbox) - auth_mode: OAUTH2 - authorization_url: https://sandbox-lever.auth0.com/authorize - token_url: https://sandbox-lever.auth0.com/oauth/token - authorization_params: - response_type: code - prompt: consent - audience: https://api.sandbox.lever.co/v1/ - proxy: - base_url: https://api.sandbox.lever.co - docs: https://docs.nango.dev/integrations/all/lever - -lever-basic-sandbox: - display_name: Lever (basic auth) (sandbox) - auth_mode: BASIC - proxy: - base_url: https://api.sandbox.lever.co - docs: https://docs.nango.dev/integrations/all/lever - credentials: - username: - type: string - title: User name - description: The API Key of your Lever sandbox account - password: - type: string - title: '' - description: '' - default_value: '' - hidden: true - -linear: - display_name: Linear - categories: - - productivity - - ticketing - auth_mode: OAUTH2 - authorization_url: https://linear.app/oauth/authorize - token_url: https://api.linear.app/oauth/token - scope_separator: ',' - authorization_params: - prompt: consent - proxy: - base_url: https://api.linear.app - retry: - at: 'x-ratelimit-requests-reset' - remaining: 'x-ratelimit-requests-remaining' - error_code: 400 - disable_pkce: true - webhook_routing_script: linearWebhookRouting - post_connection_script: linearPostConnection - webhook_user_defined_secret: true - docs: https://docs.nango.dev/integrations/all/linear - -linkedin: - display_name: LinkedIn - categories: - - ats - - social - auth_mode: OAUTH2 - authorization_url: https://www.linkedin.com/oauth/v2/authorization - token_url: https://www.linkedin.com/oauth/v2/accessToken - disable_pkce: true - proxy: - base_url: https://api.linkedin.com - docs: https://docs.nango.dev/integrations/all/linkedin - -linkhut: - display_name: LinkHut - auth_mode: OAUTH2 - authorization_url: https://ln.ht/_/oauth/authorize - token_url: https://api.ln.ht/v1/oauth/token - proxy: - base_url: https://api.ln.ht - docs: https://docs.nango.dev/integrations/all/linkhut - -loops-so: - display_name: Loops.so - categories: - - marketing - - communication - auth_mode: API_KEY - proxy: - base_url: https://app.loops.so/api - headers: - accept: application/json - authorization: Bearer ${apiKey} - verification: - method: GET - endpoint: /v1/api-key - docs: https://docs.nango.dev/integrations/all/loops-so - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Loops.so account - pattern: '^[a-f0-9]{32}$' - example: d2d561f5ff80136f69b4b5a31b9fb3c9 - -luma: - display_name: Luma - categories: - - productivity - - ticketing - auth_mode: API_KEY - proxy: - headers: - x-luma-api-key: ${apiKey} - base_url: https://api.lu.ma - verification: - method: GET - endpoint: /public/v1/user/get-self - docs: https://docs.nango.dev/integrations/all/luma - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Luma account - -listmonk: - display_name: Listmonk - categories: - - marketing - auth_mode: BASIC - proxy: - base_url: https://${connectionConfig.domain}/api - headers: - content-type: application/json - retry: - after: 'retry-after' - verification: - method: GET - endpoint: /lists - docs: https://docs.nango.dev/integrations/all/listmonk - connection_config: - domain: - type: string - title: Domain - description: The domain of your Listmonk account - format: hostname - prefix: https:// - credentials: - username: - type: string - title: API User - description: The API user to your Listmonk account - password: - type: string - title: Token - description: The token to your Listmonk account - secret: true - -make: - display_name: Make - categories: - - productivity - auth_mode: API_KEY - proxy: - base_url: https://${connectionConfig.environmentUrl}/api/v2 - headers: - authorization: Token ${apiKey} - verification: - method: GET - endpoint: /users/me - docs: https://docs.nango.dev/integrations/all/make - connection_config: - environmentUrl: - type: string - title: Domain - description: The domain of your Make account - format: hostname - prefix: https:// - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Make account - -mailgun: - display_name: Mailgun - categories: - - marketing - auth_mode: BASIC - proxy: - base_url: https://${connectionConfig.region}.mailgun.net - verification: - method: GET - endpoint: /v4/domains - docs: https://docs.nango.dev/integrations/all/mailgun - connection_config: - region: - type: string - title: Region - description: The region of your Mailgun account - pattern: '^[a-z]+$' - example: us - -mailchimp: - display_name: Mailchimp - categories: - - marketing - - surveys - auth_mode: OAUTH2 - authorization_url: https://login.mailchimp.com/oauth2/authorize - token_url: https://login.mailchimp.com/oauth2/token - authorization_params: - response_type: code - proxy: - base_url: https://${connectionConfig.dc}.api.mailchimp.com - docs: https://docs.nango.dev/integrations/all/mailchimp - connection_config: - dc: - type: string - title: Data Center - description: The data center for your account - pattern: '^[a-z]+\d*$' - example: us6 - -# Untested configuration. Please reach out if you have a test account that we can use to test it. -manatal: - display_name: Manatal - auth_mode: API_KEY - categories: - - crm - - hr - proxy: - base_url: https://api.manatal.com/open/v3 - verification: - method: GET - endpoint: /users - headers: - authorization: Token ${apiKey} - paginate: - type: link - limit_name_in_request: page_size - link_path_in_response_body: next - response_path: results - docs: https://docs.nango.dev/integrations/all/manatal - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Manatal account - -marketo: - display_name: Marketo - auth_mode: OAUTH2_CC - proxy: - base_url: https://${connectionConfig.endpointURL} - token_url: https://${connectionConfig.identityURL}/identity/oauth/token - token_params: - grant_type: client_credentials - docs: https://docs.nango.dev/integrations/all/marketo - connection_config: - endpointURL: - type: string - title: Domain - description: The domain of your Marketo account - format: hostname - example: xxx.mktorest.com - prefix: https:// - suffix: / - order: 1 - identityURL: - type: string - title: Identity URL - description: The identity URL of your Marketo account - format: hostname - prefix: https:// - example: xxx.mktorest.com - suffix: /identity/oauth/token - order: 2 - -malwarebytes: - display_name: Malwarebytes - categories: - - other - auth_mode: OAUTH2_CC - token_url: https://api.malwarebytes.com/oauth2/token - token_request_auth_method: basic - scope_separator: ' ' - token_params: - grant_type: client_credentials - proxy: - base_url: https://api.malwarebytes.com - headers: - accountid: ${connectionConfig.accountId} - connection_config: - accountId: - type: string - title: Account Id - description: Your Nebula account id - pattern: '[\da-fA-F]{8}-?[\da-fA-F]{4}-?[\da-fA-F]{4}-?[\da-fA-F]{4}-?[\da-fA-F]{12}$' - example: 9256034b-7967-4253-a5d9-260663e4fa4f - order: 1 - doc_section: '#step-1-finding-your-account-id' - - docs: https://docs.nango.dev/integrations/all/malwarebytes - docs_connect: https://docs.nango.dev/integrations/all/malwarebytes/connect - -medallia: - display_name: Medallia - categories: - - crm - - support - - surveys - auth_mode: OAUTH2_CC - token_url: https://${connectionConfig.reportingInstance}/oauth/${connectionConfig.tenantName}/token - token_request_auth_method: basic - token_params: - grant_type: client_credentials - proxy: - retry: - after: 'x-ratelimit-reset' - base_url: https://${connectionConfig.gatewayUrl}.apis.medallia.com - docs: https://docs.nango.dev/integrations/all/medallia - connection_config: - reportingInstance: - type: string - title: Domain - description: The domain of your Medallia account - format: hostname - prefix: https:// - tenantName: - type: string - title: Tenant Name - description: The tenant name of your Medallia account - gatewayUrl: - type: string - title: Gateway URL - description: The gateway URL of your Medallia account - format: hostname - prefix: https:// - -metabase: - display_name: Metabase - categories: - - analytics - auth_mode: API_KEY - proxy: - base_url: https://${connectionConfig.domain}.com - headers: - x-api-key: ${apiKey} - verification: - method: GET - endpoint: /api/database - docs: https://docs.nango.dev/integrations/all/metabase - connection_config: - domain: - type: string - title: Metabase Domain - description: The domain (without the extension) of your Metabase account - pattern: '^[a-z0-9.-]+$' - example: metabase - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Metabase account - -microsoft: - display_name: Microsoft - auth_mode: OAUTH2 - authorization_url: https://login.microsoftonline.com/common/oauth2/v2.0/authorize - token_url: https://login.microsoftonline.com/common/oauth2/v2.0/token - disable_pkce: true - default_scopes: - - offline_access - authorization_params: - response_type: code - response_mode: query - prompt: consent - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://graph.microsoft.com - retry: - after: 'retry-after' - decompress: true - docs: https://docs.nango.dev/integrations/all/microsoft - -microsoft-teams: - display_name: Microsoft Teams - categories: - - productivity - - video - alias: microsoft - webhook_routing_script: microsoftTeamsWebhookRouting - post_connection_script: microsoftTeamsPostConnection - docs: https://docs.nango.dev/integrations/all/microsoft-teams - -microsoft-tenant-specific: - display_name: Microsoft (tenant) - categories: - - erp - auth_mode: OAUTH2 - authorization_url: https://login.microsoftonline.com/${connectionConfig.tenant}/oauth2/v2.0/authorize - token_url: https://login.microsoftonline.com/${connectionConfig.tenant}/oauth2/v2.0/token - disable_pkce: true - default_scopes: - - offline_access - authorization_params: - response_type: code - response_mode: query - prompt: consent - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://graph.microsoft.com - docs: https://docs.nango.dev/integrations/all/microsoft-tenant-specific - connection_config: - tenant: - type: string - title: Tenant - description: The tenant of your Microsoft account - -microsoft-business-central: - display_name: Microsoft Business Central - categories: - - erp - auth_mode: OAUTH2_CC - token_url: https://login.microsoftonline.com/${connectionConfig.tenantId}/oauth2/v2.0/token - token_params: - grant_type: client_credentials - proxy: - base_url: https://api.businesscentral.dynamics.com/v2.0/${connectionConfig.tenantId}/${connectionConfig.environmentName} - docs: https://docs.nango.dev/integrations/all/microsoft-business-central - docs_connect: https://docs.nango.dev/integrations/all/microsoft-business-central/connect - connection_config: - tenantId: - type: string - title: Tenant ID - description: The unique identifier for your organization that uses Microsoft services - format: uuid - example: a1b2c3d4-e5f6-47a8-9b0c-d1234567890f - doc_section: '#step-1-finding-your-tenant-id' - order: 1 - environmentName: - type: string - title: Enrivonment Name - description: The environment name to your organization - example: production - pattern: '^[a-zA-Z0-9-_]+$' - doc_section: '#step-2-finding-your-enrivonment-name' - order: 2 - -microsoft-ads: - display_name: Microsoft Ads - alias: microsoft - categories: - - marketing - default_scopes: - - https://ads.microsoft.com/msads.manage - - offline_access - proxy: - base_url: https://clientcenter.api.bingads.microsoft.com/Api - refresh_params: - grant_type: refresh_token - scope: https://ads.microsoft.com/msads.manage - docs: https://docs.nango.dev/integrations/all/microsoft-ads - -microsoft-entra-id: - display_name: Microsoft Entra ID - categories: - - other - alias: microsoft - docs: https://docs.nango.dev/integrations/all/microsoft-entra-id - -microsoft-power-bi: - display_name: Microsoft Power BI - categories: - - productivity - alias: microsoft - proxy: - base_url: https://api.powerbi.com - docs: https://docs.nango.dev/integrations/all/microsoft-power-bi - -mindbody: - display_name: Mindbody (api key) - categories: - - productivity - auth_mode: API_KEY - proxy: - base_url: https://api.mindbodyonline.com - headers: - api-key: ${apiKey} - siteid: ${connectionConfig.siteId} - authorization: ${connectionConfig.staffUserToken} - verification: - method: GET - endpoint: /public/v6/site/locations - docs: https://docs.nango.dev/integrations/all/mindbody - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Mindbody account - pattern: '^[a-f0-9]{32}$' - example: a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4 - connection_config: - siteId: - type: string - title: Site ID - description: The site ID for your Mindbody account - pattern: '^\d+$' - example: '-99' - staffUserToken: - type: string - title: Staff User Token - description: The staff user token for your Mindbody account - pattern: '^[a-f0-9]{32}$' - example: a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4 - -mixpanel: - display_name: Mixpanel - categories: - - analytics - auth_mode: BASIC - proxy: - base_url: https://mixpanel.com - credentials: - # https://developer.mixpanel.com/reference/service-accounts - username: - type: string - title: Service Account Username - description: Mixpanel Service Account Username - doc_section: '#step-1-finding-mixpanel-api-key' - password: - type: string - title: Service Account Secret - description: Mixpanel Service Account Secret - doc_section: '#step-1-finding-mixpanel-api-key' - docs: https://docs.nango.dev/integrations/all/mixpanel - docs_connect: https://docs.nango.dev/integrations/all/mixpanel/connect - -miro: - display_name: Miro - categories: - - design - - productivity - auth_mode: OAUTH2 - authorization_url: https://miro.com/oauth/authorize - token_url: https://api.miro.com/v1/oauth/token - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://api.miro.com - docs: https://docs.nango.dev/integrations/all/miro - -miro-scim: - display_name: Miro (SCIM API) - categories: - - design - - productivity - auth_mode: API_KEY - proxy: - base_url: https://miro.com/api - verification: - method: GET - endpoint: /v1/scim/Users - headers: - authorization: Bearer ${apiKey} - docs: https://docs.nango.dev/integrations/all/miro - docs_connect: https://docs.nango.dev/integrations/all/miro-scim/connect - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Miro scim account - doc_section: '#step-1-finding-miro-api-key' - -monday: - display_name: Monday - categories: - - productivity - - ticketing - auth_mode: OAUTH2 - authorization_url: https://auth.monday.com/oauth2/authorize - token_url: https://auth.monday.com/oauth2/token - proxy: - base_url: https://api.monday.com - docs: https://docs.nango.dev/integrations/all/monday - -mural: - display_name: Mural - categories: - - design - auth_mode: OAUTH2 - authorization_url: https://app.mural.co/api/public/v1/authorization/oauth2 - token_url: https://app.mural.co/api/public/v1/authorization/oauth2/token - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://app.mural.co - docs: https://docs.nango.dev/integrations/all/mural - -nationbuilder: - display_name: NationBuilder - auth_mode: OAUTH2 - authorization_url: https://${connectionConfig.accountId}.nationbuilder.com/oauth/authorize - token_url: https://${connectionConfig.accountId}.nationbuilder.com/oauth/token - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - default_scopes: - - default - docs: https://docs.nango.dev/integrations/all/nationbuilder - proxy: - base_url: https://${connectionConfig.accountId}.nationbuilder.com/api - connection_config: - accountId: - type: string - title: Account ID - description: The account ID of your NationBuilder account - -netsuite: - display_name: NetSuite - categories: - - accounting - - erp - auth_mode: OAUTH2 - authorization_url: https://${connectionConfig.accountId}.app.netsuite.com/app/login/oauth2/authorize.nl - authorization_params: - prompt: consent - token_url: https://${connectionConfig.accountId}.suitetalk.api.netsuite.com/services/rest/auth/oauth2/v1/token - default_scopes: - - rest_webservices - proxy: - base_url: https://${connectionConfig.accountId}.suitetalk.api.netsuite.com/services/rest/record/v1 - retry: - after: 'retry-after' - docs: https://docs.nango.dev/integrations/all/netsuite - connection_config: - accountId: - type: string - title: Account ID - description: The account ID of your NetSuite account - pattern: '^[a-zA-Z0-9-_]+$' - example: tstdrv231585 - -netsuite-tba: - alias: netsuite - display_name: NetSuite (tba) - auth_mode: TBA - docs: https://docs.nango.dev/integrations/all/netsuite - -next-cloud-ocs: - display_name: Next Cloud OCS - auth_mode: BASIC - proxy: - base_url: https://${connectionConfig.domain}/ocs/v1.php - headers: - 'ocs-apirequest': 'true' - docs: http://docs.nango.dev/integrations/all/next-cloud - connection_config: - domain: - type: string - title: Domain - description: The domain of your Next Cloud account - format: hostname - prefix: https:// - -notion: - display_name: Notion - categories: - - knowledge-base - - productivity - auth_mode: OAUTH2 - authorization_url: https://api.notion.com/v1/oauth/authorize - token_url: https://api.notion.com/v1/oauth/token - authorization_params: - response_type: code - owner: user - authorization_method: header - body_format: json - proxy: - retry: - after: 'retry-after' - base_url: https://api.notion.com - headers: - 'notion-version': '2022-06-28' - paginate: - type: cursor - cursor_path_in_response: next_cursor - cursor_name_in_request: start_cursor - limit_name_in_request: page_size - response_path: results - docs: https://docs.nango.dev/integrations/all/notion - -notion-scim: - display_name: Notion (SCIM API) - categories: - - knowledge-base - - productivity - auth_mode: API_KEY - proxy: - base_url: https://api.notion.com/scim - verification: - method: GET - endpoint: /v2/Users - headers: - authorization: Bearer ${apiKey} - docs: https://docs.nango.dev/integrations/all/notion - docs_connect: https://docs.nango.dev/integrations/all/notion-scim/connect - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Notion scim account - doc_section: '#step-1-finding-your-scim-api-key-token' - -odoo: - display_name: Odoo - categories: - - erp - auth_mode: OAUTH2 - authorization_url: https://${connectionConfig.serverUrl}/restapi/1.0/common/oauth2/authorize - token_url: https://${connectionConfig.serverUrl}/restapi/1.0/common/oauth2/access_token - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://${connectionConfig.serverUrl} - docs: https://docs.nango.dev/integrations/all/odoo - connection_config: - serverUrl: - type: string - title: Domain - description: The domain of your Odoo account - format: hostname - prefix: https:// - -okta: - display_name: Okta - auth_mode: OAUTH2 - authorization_url: https://${connectionConfig.subdomain}.okta.com/oauth2/v1/authorize - token_url: https://${connectionConfig.subdomain}.okta.com/oauth2/v1/token - authorization_params: - response_type: code - response_mode: query - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://${connectionConfig.subdomain}.okta.com - retry: - at: 'x-rate-limit-reset' - paginate: - type: 'link' - limit_name_in_request: 'limit' - link_rel_in_response_header: 'next' - docs: https://docs.nango.dev/integrations/all/okta - connection_config: - subdomain: - type: string - title: Okta Domain - description: The subdomain of your Okta account - pattern: '^[a-z0-9_-]+$' - example: domain - suffix: .okta.com - prefix: https:// - -okta-preview: - alias: okta - display_name: Okta (Preview) - authorization_url: https://${connectionConfig.subdomain}.oktapreview.com/oauth2/v1/authorize - token_url: https://${connectionConfig.subdomain}.oktapreview.com/oauth2/v1/token - proxy: - base_url: https://${connectionConfig.subdomain}.oktapreview.com - docs: https://docs.nango.dev/integrations/all/okta - connection_config: - subdomain: - type: string - title: Okta Preview Domain - description: The subdomain of your Okta Preview account - pattern: '^[a-z0-9_-]+$' - example: domain - suffix: .oktapreview.com - prefix: https:// - -one-drive: - display_name: One Drive - categories: - - knowledge-base - - storage - alias: microsoft - docs: https://docs.nango.dev/integrations/all/one-drive - -one-note: - display_name: One Note - categories: - - productivity - alias: microsoft - docs: https://docs.nango.dev/integrations/all/one-note - -openai: - display_name: OpenAI - categories: - - productivity - - dev-tools - auth_mode: API_KEY - proxy: - base_url: https://api.openai.com - headers: - authorization: Bearer ${apiKey} - content-type: application/json - verification: - method: GET - endpoint: /v1/models - retry: - after: 'x-ratelimit-reset-requests' - docs: https://docs.nango.dev/integrations/all/openai - credentials: - apiKey: - type: string - title: API Key - description: The API key for your OpenAI account - -ory: - display_name: Ory - categories: - - other - auth_mode: OAUTH2_CC - proxy: - base_url: https://${connectionConfig.projectSlug}.projects.oryapis.com - token_url: https://${connectionConfig.projectSlug}.projects.oryapis.com/oauth2/token - scope_separator: ' ' - token_params: - grant_type: client_credentials - docs: https://docs.nango.dev/integrations/all/ory - connection_config: - projectSlug: - type: string - title: Project Slug - description: The project slug of your Ory project - -osu: - display_name: Osu - categories: - - gaming - auth_mode: OAUTH2 - authorization_url: https://osu.ppy.sh/oauth/authorize - token_url: https://osu.ppy.sh/oauth/token - default_scopes: - - identify - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://osu.ppy.sh - docs: https://docs.nango.dev/integrations/all/osu - -oura: - display_name: Oura - categories: - - sports - auth_mode: OAUTH2 - authorization_url: https://cloud.ouraring.com/oauth/authorize - token_url: https://api.ouraring.com/oauth/token - scope_separator: ' ' - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://api.ouraring.com - docs: https://docs.nango.dev/integrations/all/oura - -outlook: - display_name: Outlook - categories: - - communication - alias: microsoft - docs: https://docs.nango.dev/integrations/all/outlook - -outreach: - display_name: Outreach - categories: - - marketing - auth_mode: OAUTH2 - authorization_url: https://api.outreach.io/oauth/authorize - token_url: https://api.outreach.io/oauth/token - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://api.outreach.io - docs: https://docs.nango.dev/integrations/all/outreach - -pagerduty: - display_name: PagerDuty - categories: - - dev-tools - auth_mode: OAUTH2 - authorization_url: https://app.pagerduty.com/oauth/authorize - token_url: https://app.pagerduty.com/oauth/token - proxy: - base_url: https://api.pagerduty.com - docs: https://docs.nango.dev/integrations/all/pagerduty - -pandadoc: - display_name: Pandadoc - categories: - - legal - auth_mode: OAUTH2 - authorization_url: https://app.pandadoc.com/oauth2/authorize - token_url: https://api.pandadoc.com/oauth2/access_token - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://api.pandadoc.com - docs: https://docs.nango.dev/integrations/all/pandadoc - -payfit: - display_name: Payfit - categories: - - hr - auth_mode: OAUTH2 - authorization_url: https://oauth.payfit.com/authorize - token_url: https://app.pagerduty.com/oauth/token - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - proxy: - base_url: https://partner-api.payfit.com - docs: https://docs.nango.dev/integrations/all/payfit - -paypal: - display_name: Paypal - categories: - - payment - auth_mode: OAUTH2 - authorization_url: https://www.paypal.com/signin/authorize - token_url: https://api.paypal.com/v1/oauth2/token - token_request_auth_method: basic - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://api-m.paypal.com - docs: https://docs.nango.dev/integrations/all/paypal - -paypal-sandbox: - display_name: Paypal (sandbox) - auth_mode: OAUTH2 - authorization_url: https://www.sandbox.paypal.com/signin/authorize - token_url: https://api-m.sandbox.paypal.com/v1/oauth2/token - token_request_auth_method: basic - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://api-m.sandbox.paypal.com - docs: https://docs.nango.dev/integrations/all/paypal - -pendo: - display_name: Pendo - categories: - - analytics - auth_mode: API_KEY - proxy: - base_url: https://app.pendo.io - verification: - method: GET - endpoint: /api/v1/page - headers: - x-pendo-integration-key: ${apiKey} - docs: https://docs.nango.dev/integrations/all/pendo - docs_connect: https://docs.nango.dev/integrations/all/pendo/connect - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Pendo account - doc_section: '#step-1-finding-pendo-api-key' - -pennylane: - display_name: Pennylane - categories: - - accounting - - banking - - invoicing - - payment - auth_mode: OAUTH2 - authorization_url: https://app.pennylane.com/oauth/authorize - token_url: https://app.pennylane.com/oauth/token - proxy: - base_url: https://app.pennylane.com - scope_separator: '+' - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - authorization_url_skip_encode: - - scopes - docs: https://docs.nango.dev/integrations/all/pennylane - -peopledatalabs: - display_name: People Data Labs - categories: - - analytics - auth_mode: API_KEY - proxy: - base_url: https://api.peopledatalabs.com - query: - api_key: ${apiKey} - docs: https://docs.nango.dev/integrations/all/peopledatalabs - credentials: - apiKey: - type: string - title: API Key - description: The API key for your People Data Labs account - -perplexity: - display_name: Perplexity - categories: - - productivity - - dev-tools - auth_mode: API_KEY - proxy: - headers: - authorization: Bearer ${apiKey} - base_url: https://api.perplexity.ai - docs: https://docs.nango.dev/integrations/all/perplexity - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Perplexity account - pattern: '^pplx-[a-f0-9]+$' - example: pplx-xxxxxx - -perimeter81: - display_name: Perimeter81 - categories: - - productivity - auth_mode: TWO_STEP - proxy: - base_url: https://api.perimeter81.com/api/rest - token_url: https://api.${connectionConfig.domain}.com/api/v1/auth/authorize - token_params: - apiKey: ${credential.apiKey} - grantType: api_key - token_headers: - content-type: application/json - token_response: - token: data.accessToken - token_expiration: data.accessTokenExpire - token_expiration_strategy: expireAt - docs: https://docs.nango.dev/integrations/all/perimeter81 - docs_connect: https://docs.nango.dev/integrations/all/perimeter81/connect - connection_config: - domain: - type: string - title: Domain - description: The domain for Perimeter81 - pattern: '^(perimeter81|eu\.sase\.checkpoint)$' - example: '(perimeter81,eu.sase.checkpoint)' - doc_section: '#step-1-finding-your-perimeter81-domain-and-perimeter81-api-key' - suffix: .com - prefix: https://api. - order: 1 - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Perimeter81 account - secret: true - -personio: - display_name: Personio - categories: - - hr - auth_mode: OAUTH2_CC - proxy: - base_url: https://api.personio.de/v1 - headers: - x-personio-partner-id: ${connectionConfig.partnerId} - x-personio-app-id: ${connectionConfig.appId} - token_url: https://api.personio.de/v1/auth - body_format: json - docs: https://docs.nango.dev/integrations/all/personio - docs_connect: https://docs.nango.dev/integrations/all/personio/connect - connection_config: - partnerId: - type: string - title: Partner ID - description: The partner ID of your Personio account - doc_section: '#step-1-finding-personio-client-id' - appId: - type: string - title: App ID - description: The app ID of your Personio account - doc_section: '#step-2-finding-personio-client-secret' - -personio-v2: - display_name: Personio (v2) - categories: - - hr - auth_mode: OAUTH2_CC - proxy: - base_url: https://api.personio.de/v2 - headers: - content-type: application/x-www-form-urlencoded - token_url: https://api.personio.de/v2/auth/token - scope_separator: ' ' - docs: https://docs.nango.dev/integrations/all/personio - token_params: - grant_type: client_credentials - -personio-recruiting: - display_name: Personio Recruiting - categories: - - hr - auth_mode: API_KEY - proxy: - base_url: https://api.personio.de/v1 - headers: - authorization: Bearer ${apiKey} - x-company-id: ${connectionConfig.companyId} - x-personio-partner-id: ${connectionConfig.partnerId} - x-personio-app-id: ${connectionConfig.appId} - verification: - method: GET - endpoint: /xml?language=en - base_url_override: https://${connectionConfig.company}.jobs.personio.de - headers: - accept: application/xml - content-type: xml - docs: https://docs.nango.dev/integrations/all/personio - connection_config: - companyId: - type: string - title: Company ID - description: The company ID of your Personio account - company: - type: string - title: Company Name - description: The company name of your Personio account - partnerId: - type: string - title: Partner ID - description: The partner ID of your Personio account - appId: - type: string - title: App ID - description: The app ID of your Personio account - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Pingboard account - -pingboard: - display_name: Pingboard - categories: - - productivity - auth_mode: OAUTH2_CC - proxy: - base_url: https://app.pingboard.com/api/v2 - token_url: https://app.pingboard.com/oauth/token - scope_separator: ' ' - token_params: - grant_type: client_credentials - docs: https://docs.nango.dev/integrations/all/pingboard - -pinterest: - display_name: Pinterest - categories: - - design - - marketing - - social - - video - auth_mode: OAUTH2 - authorization_url: https://www.pinterest.com/oauth - token_url: https://api.pinterest.com/v5/oauth/token - token_request_auth_method: basic - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://api.pinterest.com - docs: https://docs.nango.dev/integrations/all/pinterest - -pipedrive: - display_name: Pipedrive - categories: - - crm - auth_mode: OAUTH2 - authorization_url: https://oauth.pipedrive.com/oauth/authorize - token_url: https://oauth.pipedrive.com/oauth/token - token_response_metadata: - - api_domain - proxy: - base_url: ${connectionConfig.api_domain}/api - decompress: true - paginate: - type: offset - offset_name_in_request: start - response_path: data - limit_name_in_request: limit - docs: https://docs.nango.dev/integrations/all/pipedrive - connection_config: - api_domain: - type: string - title: API URL - description: The API URL of your Pipedrive account - format: uri - pattern: '^https?://.*$' - -pivotaltracker: - display_name: Pivotal Tracker - categories: - - productivity - auth_mode: API_KEY - proxy: - headers: - x-trackertoken: ${apiKey} - base_url: https://www.pivotaltracker.com/services/v5 - verification: - method: GET - endpoint: /accounts - docs: https://docs.nango.dev/integrations/all/pivotaltracker - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Pivotal Tracker account - -plain: - display_name: Plain - categories: - - support - auth_mode: API_KEY - proxy: - headers: - authorization: Bearer ${apiKey} - base_url: https://core-api.uk.plain.com/graphql/v1 - verification: - method: GET - endpoint: ?query=%7B__schema%7Btypes%7Bname,kind,fields%7Bname%7D%7D%7D%7D - docs: https://docs.nango.dev/integrations/all/plain - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Plain account - -podium: - display_name: Podium - categories: - - communication - - marketing - auth_mode: OAUTH2 - authorization_url: https://api.podium.com/oauth/authorize - token_url: https://api.podium.com/oauth/token - scope_separator: ' ' - body_format: json - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - headers: - podium-version: ${connectionConfig.apiVersion} - content-type: application/json - base_url: https://api.podium.com - retry: - after: 'x-ratelimit-reset' - docs: https://docs.nango.dev/integrations/all/podium - connection_config: - apiVersion: - type: string - title: API Version - description: The API version of your Podium account - -posthog: - display_name: PostHog - categories: - - dev-tools - auth_mode: API_KEY - proxy: - headers: - authorization: Bearer ${apiKey} - base_url: https://${connectionConfig.subdomain}.posthog.com - verification: - method: GET - endpoint: /api/users/@me - docs: https://docs.nango.dev/integrations/all/posthog - docs_connect: https://docs.nango.dev/integrations/all/posthog/connect - connection_config: - subdomain: - type: string - title: PostHog Domain - description: The subdomain of your PostHog account - pattern: '^[a-z0-9_-]+$' - example: domain - suffix: .posthog.com - prefix: https:// - credentials: - apiKey: - type: string - title: API Key - description: The API key for your PostHog account - doc_section: '#step-1-finding-your-posthog-api-key' - -productboard: - display_name: Productboard - categories: - - productivity - auth_mode: OAUTH2 - authorization_url: https://app.productboard.com/oauth2/authorize - token_url: https://app.productboard.com/oauth2/token - scope_separator: ' ' - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - headers: - x-version: '1' - base_url: https://api.productboard.com - docs: https://docs.nango.dev/integrations/all/productboard - -qualtrics: - display_name: Qualtrics - categories: - - surveys - auth_mode: OAUTH2 - authorization_url: https://${connectionConfig.subdomain}.qualtrics.com/oauth2/auth - token_url: https://${connectionConfig.subdomain}.qualtrics.com/oauth2/token - proxy: - base_url: https://${connectionConfig.subdomain}.qualtrics.com - docs: https://docs.nango.dev/integrations/all/qualtrics - connection_config: - subdomain: - type: string - title: Qualtrics Domain - description: The subdomain of your Qualtrics account - pattern: '^[a-z0-9_-]+$' - example: domain - suffix: .qualtrics.com - prefix: https:// - -quickbooks: - display_name: Quickbooks - categories: - - accounting - auth_mode: OAUTH2 - authorization_url: https://appcenter.intuit.com/connect/oauth2 - token_url: https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer - redirect_uri_metadata: - - realmId - proxy: - connection_config: - realmId: ${connectionConfig.realmId} - base_url: https://quickbooks.api.intuit.com - docs: https://docs.nango.dev/integrations/all/quickbooks - docs_connect: https://docs.nango.dev/integrations/all/quickbooks/connect - connection_config: - realmId: - type: string - title: Quickbooks Realm ID - optional: true - description: The realmId of your quickbooks company - pattern: '^\d{16}$' - example: '9341453474484455' - doc_section: '#step-1-finding-your-realm-id' - -quickbooks-sandbox: - alias: quickbooks - display_name: Quickbooks (sandbox) - proxy: - connection_config: - realmId: ${connectionConfig.realmId} - base_url: https://sandbox-quickbooks.api.intuit.com - docs: https://docs.nango.dev/integrations/all/quickbooks - docs_connect: https://docs.nango.dev/integrations/all/quickbooks-sandbox/connect - connection_config: - realmId: - type: string - title: Quickbooks Realm ID - optional: true - description: The realmId of your quickbooks sandbox company - pattern: '^\d{16}$' - example: '9341453474484455' - doc_section: '#step-1-finding-your-realm-id' - -ragieai: - display_name: Ragie AI - categories: - - dev-tools - auth_mode: API_KEY - proxy: - base_url: https://api.ragie.ai - headers: - authorization: Bearer ${apiKey} - verification: - method: GET - endpoint: /documents - docs: https://docs.nango.dev/integrations/all/ragieai - credentials: - apiKey: - type: string - title: API Key - description: The API key for your ragie.ai account - example: tnt_IZ56tqGVgX9_k8CKnxQ9MvQgzDXcDGgtcjXABkwusxSOR8QzwxxeA1B - pattern: '^tnt_[a-zA-Z0-9_]+$' - -ramp: - display_name: Ramp - categories: - - banking - auth_mode: OAUTH2 - authorization_url: https://app.ramp.com/v1/authorize - token_url: https://api.ramp.com/developer/v1/token - authorization_method: header - proxy: - base_url: https://api.ramp.com - docs: https://docs.nango.dev/integrations/all/ramp - -ramp-sandbox: - display_name: Ramp (sandbox) - auth_mode: OAUTH2 - authorization_url: https://demo.ramp.com/v1/authorize - token_url: https://demo-api.ramp.com/developer/v1/token - authorization_method: header - proxy: - base_url: https://demo-api.ramp.com - docs: https://docs.nango.dev/integrations/all/ramp - -rapidapi: - display_name: RapidAPI - categories: - - dev-tools - auth_mode: API_KEY - proxy: - headers: - x-rapidapi-key: ${apiKey} - x-rapidapi-host: ${connectionConfig.subdomain}.p.rapidapi.com - base_url: https://${connectionConfig.subdomain}.p.rapidapi.com - docs: https://docs.nango.dev/integrations/all/rapidapi - credentials: - apiKey: - type: string - title: API Key - description: The API key for your RapidAPI account - example: b7c156af2dmgh5c635305f3744bap168553jsp75193c8367ef - pattern: '^[a-zA-Z0-9]+$' - connection_config: - subdomain: - type: string - title: Subdomain - description: The subdomain of the Rapid API. - pattern: '^[a-z0-9_-]+$' - example: api-football-v1 - suffix: .p.rapidapi.com - prefix: https:// - -reddit: - display_name: Reddit - categories: - - social - auth_mode: OAUTH2 - authorization_url: https://www.reddit.com/api/v1/authorize - token_url: https://www.reddit.com/api/v1/access_token - authorization_method: header - authorization_params: - duration: permanent - proxy: - base_url: https://oauth.reddit.com - docs: https://docs.nango.dev/integrations/all/reddit - -refiner: - display_name: Refiner - categories: - - surveys - auth_mode: API_KEY - proxy: - headers: - authorization: Bearer ${apiKey} - base_url: https://api.refiner.io/v1 - verification: - method: GET - endpoint: /account - docs: https://docs.nango.dev/integrations/all/refiner - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Refiner account - -replicate: - display_name: Replicate - auth_mode: API_KEY - proxy: - headers: - authorization: Bearer ${apiKey} - base_url: https://api.replicate.com - verification: - method: GET - endpoint: /v1/account - docs: https://docs.nango.dev/integrations/all/replicate - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Replicate account - -ring-central: - display_name: RingCentral - categories: - - support - auth_mode: OAUTH2 - authorization_url: https://platform.ringcentral.com/restapi/oauth/authorize - token_url: https://platform.ringcentral.com/restapi/oauth/token - authorization_method: header - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://platform.ringcentral.com - docs: https://docs.nango.dev/integrations/all/ring-central - -ring-central-sandbox: - display_name: RingCentral (sandbox) - auth_mode: OAUTH2 - authorization_url: https://platform.devtest.ringcentral.com/restapi/oauth/authorize - token_url: https://platform.devtest.ringcentral.com/restapi/oauth/token - authorization_method: header - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://platform.devtest.ringcentral.com - docs: https://docs.nango.dev/integrations/all/ring-central - -segment: - display_name: Segment - categories: - - analytics - - marketing - auth_mode: OAUTH2 - authorization_url: https://id.segmentapis.com/oauth2/auth - token_url: https://id.segmentapis.com/oauth2/token - token_request_auth_method: basic - proxy: - base_url: https://api.segment.io - docs: https://docs.nango.dev/integrations/all/segment - -sage: - display_name: Sage - categories: - - accounting - - erp - auth_mode: OAUTH2 - authorization_url: https://www.sageone.com/oauth2/auth/central - token_url: https://oauth.accounting.sage.com/token - authorization_params: - filter: apiv3.1 - proxy: - base_url: https://api.accounting.sage.com - docs: https://docs.nango.dev/integrations/all/sage - -sage-intacct: - display_name: Sage Intacct - categories: - - accounting - - erp - auth_mode: TWO_STEP - proxy: - base_url: https://api.intacct.com/ia/xml/xmlgw.phtml - token_url: https://api.intacct.com/ia/xml/xmlgw.phtml - body_format: xml - token_params: - request: - control: - senderid: ${credential.senderId} - password: ${credential.senderPassword} - controlid: ${now} - uniqueid: false - dtdversion: '3.0' - includewhitespace: false - operation: - authentication: - login: - userid: ${credential.userId} - companyid: ${credential.companyId} - password: ${credential.userPassword} - content: - function: - $controlid: '{{$guid}}' - getAPISession: '' - token_headers: - content-type: application/xml - token_response: - token: response.operation.result.data.api.sessionid - token_expiration: response.operation.authentication.sessiontimeout - token_expiration_strategy: expireAt - docs: https://docs.nango.dev/integrations/all/sage - docs_connect: https://docs.nango.dev/integrations/all/sage-intacct/connect - credentials: - senderId: - type: string - title: Sender ID - description: Your Sage Intacct Sender ID - doc_section: '#step-1-how-to-retrieve-the-sender-id' - senderPassword: - type: string - title: Sender Password - description: Your Sage Intacct Sender Password - secret: true - userId: - type: string - title: User ID - description: Your Sage Intacct User ID - doc_section: '#step-2-how-to-retrieve-the-user-id' - companyId: - type: string - title: Company ID - description: Your Sage Intacct Company ID - doc_section: '#step-3-how-to-retrieve-the-company-id' - userPassword: - type: string - title: User Password - description: Your Sage Intacct User Password - secret: true - -salesforce: - display_name: Salesforce - categories: - - crm - auth_mode: OAUTH2 - authorization_url: https://login.salesforce.com/services/oauth2/authorize - token_url: https://login.salesforce.com/services/oauth2/token - authorization_params: - prompt: consent - default_scopes: - - offline_access - token_response_metadata: - - instance_url - proxy: - base_url: ${connectionConfig.instance_url} - webhook_routing_script: salesforceWebhookRouting - post_connection_script: salesforcePostConnection - docs: https://docs.nango.dev/integrations/all/salesforce - connection_config: - instance_url: - type: string - title: Instance URL - description: The instance URL of your Salesforce account - format: uri - pattern: '^https?://.*$' - automated: true - -salesforce-sandbox: - display_name: Salesforce (sandbox) - auth_mode: OAUTH2 - authorization_url: https://test.salesforce.com/services/oauth2/authorize - token_url: https://test.salesforce.com/services/oauth2/token - default_scopes: - - offline_access - token_response_metadata: - - instance_url - proxy: - base_url: ${connectionConfig.instance_url} - docs: https://docs.nango.dev/integrations/all/salesforce - connection_config: - instance_url: - type: string - title: Instance URL - description: The instance URL of your Salesforce account - format: uri - pattern: '^https?://.*$' - automated: true - -salesforce-experience-cloud: - display_name: Salesforce Experience Cloud - auth_mode: OAUTH2 - authorization_url: https://${connectionConfig.subdomain}.my.site.com/services/oauth2/authorize - token_url: https://${connectionConfig.subdomain}.my.site.com/services/oauth2/token - default_scopes: - - offline_access - token_response_metadata: - - instance_url - proxy: - base_url: ${connectionConfig.instance_url} - docs: https://docs.nango.dev/integrations/all/salesforce-experience-cloud - connection_config: - subdomain: - type: string - title: Salesforce Domain - description: The subdomain of your Salesforce Experience Cloud account - pattern: '^[a-z0-9_-]+$' - example: domain - suffix: .my.site.com - prefix: https:// - instance_url: - type: string - title: Instance URL - description: The instance URL of your Salesforce Experience Cloud account - format: uri - pattern: '^https?://.*$' - automated: true -sap-success-factors: - display_name: SAP SuccessFactors - categories: - - hr - auth_mode: TWO_STEP - token_url: https://${connectionConfig.apiServer}/oauth/token - token_params: - company_id: ${connectionConfig.companyId} - client_id: ${credential.apiKey} - grant_type: urn:ietf:params:oauth:grant-type:saml2-bearer - assertion: ${credential.assertion} - token_headers: - content-type: application/x-www-form-urlencoded - proxy: - base_url: https://${connectionConfig.apiServer} - token_response: - token: access_token - token_expiration: expires_in - token_expiration_strategy: expireIn - docs: https://docs.nango.dev/integrations/all/sap-success-factors - docs_connect: https://docs.nango.dev/integrations/all/sap-success-factors/connect - connection_config: - apiServer: - type: string - title: API Server - description: The API Server to connect to your SAP SuccessFactors account - pattern: '^[a-z0-9.-]+$' - example: api41preview.sapsf.com - prefix: https:// - doc_section: '#step-1-finding-your-api-server' - order: 1 - companyId: - type: string - title: Company ID - description: The company ID of your SAP SuccessFactors account - example: SFSALES012345 - pattern: '^[A-Z0-9]+$' - doc_section: '#step-2-finding-your-company-id' - order: 2 - credentials: - apiKey: - type: string - title: API Key - description: The API key for your SAP SuccessFactors account - secret: true - doc_section: '#step-3-generating-your-api-key' - assertion: - type: string - title: SAML Assertion - description: The SAML Assertion generated for your SAP SuccessFactors account - secret: true - doc_section: '#step-4-generating-your-saml-assertion' - -scrapedo: - display_name: Scrape.do - categories: - - other - auth_mode: API_KEY - proxy: - base_url: https://api.scrape.do - query: - token: ${apiKey} - docs: https://docs.nango.dev/integrations/all/scrapedo - docs_connect: https://docs.nango.dev/integrations/all/scrapedo/connect - credentials: - apiKey: - type: string - title: API Token - description: The API Token for your Scrape.do account - example: 3c12d71308a346c41d10b19a2b2ac1ea5cacb53588d - pattern: '^[a-zA-Z0-9]+$' - doc_section: '#step-1-finding-your-api-key' - -salesloft: - display_name: Salesloft - categories: - - marketing - auth_mode: OAUTH2 - authorization_url: https://accounts.salesloft.com/oauth/authorize - token_url: https://accounts.salesloft.com/oauth/token - proxy: - base_url: https://api.salesloft.com - docs: https://docs.nango.dev/integrations/all/salesloft - -sendgrid: - display_name: SendGrid - categories: - - marketing - auth_mode: API_KEY - proxy: - headers: - authorization: Bearer ${apiKey} - base_url: https://api.sendgrid.com - docs: https://docs.nango.dev/integrations/all/sendgrid - docs_connect: https://docs.nango.dev/integrations/all/sendgrid/connect - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Sendgrid account - doc_section: '#step-1-generating-your-sendgrid-api-key' - -sedna: - display_name: Sedna (Oauth2) - auth_mode: OAUTH2_CC - categories: - - communication - proxy: - base_url: https://${connectionConfig.tenant}.sednanetwork.com/platform - token_url: https://${connectionConfig.tenant}.sednanetwork.com/platform/oauth/token - token_params: - grant_type: client_credentials - scope_separator: ',' - docs: https://docs.nango.dev/integrations/all/sedna - connection_config: - tenant: - type: string - title: Tenant - description: The tenant name to your sedna account - -sedna-basic: - display_name: Sedna (Basic Auth) - auth_mode: BASIC - categories: - - communication - proxy: - base_url: https://${connectionConfig.tenant}.sednanetwork.com/platform - docs: https://docs.nango.dev/integrations/all/sedna - connection_config: - tenant: - type: string - title: Tenant - description: The tenant name to your sedna account - -servicem8: - display_name: ServiceM8 - categories: - - productivity - auth_mode: OAUTH2 - authorization_url: https://go.servicem8.com/oauth/authorize - token_url: https://go.servicem8.com/oauth/access_token - proxy: - base_url: https://api.servicem8.com - scope_separator: ' ' - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - docs: https://docs.nango.dev/integrations/all/servicem8 - -signnow: - display_name: SignNow - categories: - - legal - auth_mode: OAUTH2 - authorization_url: https://app.signnow.com/authorize - token_url: https://api.signnow.com/oauth2/token - disable_pkce: true - token_request_auth_method: basic - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://api.signnow.com - docs: https://docs.nango.dev/integrations/all/signnow - -signnow-sandbox: - display_name: SignNow (sandbox) - categories: - - legal - auth_mode: OAUTH2 - authorization_url: https://app-eval.signnow.com/authorize - token_url: https://api-eval.signnow.com/oauth2/token - disable_pkce: true - token_request_auth_method: basic - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://api-eval.signnow.com - docs: https://docs.nango.dev/integrations/all/signnow - -servicenow: - display_name: ServiceNow - categories: - - productivity - auth_mode: OAUTH2 - authorization_url: https://${connectionConfig.subdomain}.service-now.com/oauth_auth.do - token_url: https://${connectionConfig.subdomain}.service-now.com/oauth_token.do - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://${connectionConfig.subdomain}.service-now.com - docs: https://docs.nango.dev/integrations/all/servicenow - connection_config: - subdomain: - type: string - title: ServiceNow Domain - description: The subdomain of your ServiceNow account - pattern: '^[a-z0-9_-]+$' - example: domain - suffix: .service-now.com - prefix: https:// - -sharepoint-online: - display_name: SharePoint Online - categories: - - storage - - communication - alias: microsoft - docs: https://docs.nango.dev/integrations/all/sharepoint-online - -sharepoint-online-v1: - display_name: SharePoint Online (v1) - categories: - - storage - - communication - auth_mode: TWO_STEP - token_url: https://login.microsoftonline.com/${connectionConfig.tenantId}/oauth2/token - body_format: form - token_params: - client_id: ${credential.clientId} - grant_type: client_credentials - resource: https://${connectionConfig.tenantId}.sharepoint.com - client_assertion_type: urn:ietf:params:oauth:client-assertion-type:jwt-bearer - client_assertion: ${credential.assertion} - token_headers: - content-type: application/x-www-form-urlencoded - proxy: - base_url: https://${connectionConfig.tenantName}.sharepoint.com - headers: - accept: application/json;odata=verbose - token_response: - token: access_token - token_expiration: expires_in - token_expiration_strategy: expireIn - docs: https://docs.nango.dev/integrations/all/sharepoint-online - docs_connect: https://docs.nango.dev/integrations/all/sharepoint-online-v1/connect - connection_config: - tenantId: - type: string - title: Tenant ID - description: The unique identifier for your organization that uses Microsoft services - format: uuid - example: a1b2c3d4-e5f6-47a8-9b0c-d1234567890f - doc_section: '#step-1-finding-your-tenant-id' - order: 1 - tenantName: - type: string - title: Tenant Name - description: The initial domain name for your Microsoft services tenant - example: mycompany - pattern: '^[a-zA-Z0-9]+$' - doc_section: '#step-2-finding-your-tenant-name' - order: 2 - credentials: - clientId: - type: string - title: Client ID - description: Your application Client ID - secret: true - doc_section: '#step-3-finding-your-client-id' - assertion: - type: string - title: Client Assertion - description: Your generated client assertion - secret: true - doc_section: '#step-4-generating-your-client-assertion' - -shipstation: - display_name: Shipstation - categories: - - e-commerce - auth_mode: BASIC - proxy: - base_url: https://ssapi.shipstation.com - retry: - after: 'x-rate-limit-reset' - verification: - method: GET - endpoint: /users - docs: https://docs.nango.dev/integrations/all/shipstation - docs_connect: https://docs.nango.dev/integrations/all/shipstation/connect - credentials: - username: - type: string - title: API Key - description: Your ShipStation API key - doc_section: '#step-1-finding-shipstation-api-key-and-api-secret' - password: - type: string - title: API Secret - description: Your Shipstation API secret - # https://www.shipstation.com/docs/api/requirements/#authentication - # Shipstation is using basic auth with API key and secret - doc_section: '#step-1-finding-shipstation-api-key-and-api-secret' - -shopify: - display_name: Shopify - categories: - - e-commerce - auth_mode: OAUTH2 - authorization_url: https://${connectionConfig.subdomain}.myshopify.com/admin/oauth/authorize - token_url: https://${connectionConfig.subdomain}.myshopify.com/admin/oauth/access_token - proxy: - base_url: https://${connectionConfig.subdomain}.myshopify.com - headers: - x-shopify-access-token: ${accessToken} - docs: https://docs.nango.dev/integrations/all/shopify - docs_connect: https://docs.nango.dev/integrations/all/shopify/connect - connection_config: - subdomain: - type: string - title: Shopify Domain - description: The subdomain of your Shopify account - pattern: '^[a-z0-9_-]+$' - example: domain - suffix: .myshopify.com - prefix: https:// - doc_section: '#step-1-finding-your-shopify-domain' - -shopify-api-key: - display_name: Shopify (api key) - categories: - - e-commerce - auth_mode: API_KEY - proxy: - base_url: https://${connectionConfig.subdomain}.myshopify.com - headers: - x-shopify-access-token: ${apiKey} - content-type: application/json - verification: - method: POST - endpoint: /admin/api/2024-10/graphql.json?query=%7B__schema%7Btypes%7Bname%2Ckind%2Cfields%7Bname%7D%7D%7D%7D - docs: https://docs.nango.dev/integrations/all/shopify - docs_connect: https://docs.nango.dev/integrations/all/shopify-api-key/connect - connection_config: - subdomain: - type: string - title: Shopify Domain - description: The subdomain of your Shopify account - pattern: '^[a-z0-9_-]+$' - example: domain - suffix: .myshopify.com - prefix: https:// - doc_section: '#step-1-finding-your-shopify-domain' - order: 1 - credentials: - apiKey: - type: string - title: API Access Token - description: The API access token generated - example: shpat_***************c03266f - pattern: '^shpat_[a-f0-9]{32}$' - doc_section: '#step-2-generating-your-api-access-token' - -shopify-scim: - display_name: Shopify (SCIM API) - categories: - - e-commerce - auth_mode: API_KEY - proxy: - base_url: https://shopifyscim.com/scim - headers: - authorization: Bearer ${apiKey} - accept: application/json - content-type: application/json - retry: - after: 'retry-after' - docs: https://docs.nango.dev/integrations/all/shopify - docs_connect: https://docs.nango.dev/integrations/all/shopify-scim/connect - credentials: - apiKey: - type: string - title: SCIM API Token - description: The SCIM API token generated from your Shopify organization settings. - doc_section: '#step-1-generating-your-scim-api-token' - -shortcut: - display_name: Shortcut - categories: - - dev-tools - - productivity - auth_mode: API_KEY - proxy: - base_url: https://api.app.shortcut.com - headers: - shortcut-token: ${apiKey} - verification: - method: GET - endpoint: /v3/member - docs: https://docs.nango.dev/integrations/all/shortcut - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Shortcut account - -slack: - display_name: Slack - categories: - - productivity - auth_mode: OAUTH2 - authorization_url: https://slack.com/oauth/v2/authorize - token_url: https://slack.com/api/oauth.v2.access - token_response_metadata: - - incoming_webhook.url - - incoming_webhook.channel - - incoming_webhook.channel_id - - bot_user_id - - team.id - proxy: - base_url: https://slack.com/api - paginate: - type: cursor - cursor_path_in_response: response_metadata.next_cursor - cursor_name_in_request: cursor - limit_name_in_request: limit - webhook_routing_script: slackWebhookRouting - docs: https://docs.nango.dev/integrations/all/slack - -smartrecruiters-api-key: - display_name: Smartrecruiters (api key) - auth_mode: API_KEY - proxy: - base_url: https://api.smartrecruiters.com - headers: - x-smarttoken: ${apiKey} - verification: - method: GET - endpoint: /feed/publications - docs: https://docs.nango.dev/integrations/all/smartrecruiters - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Smartrecruiters account - -smartsheet: - display_name: Smartsheet - auth_mode: OAUTH2 - authorization_url: https://app.smartsheet.com/b/authorize - token_url: https://api.smartsheet.com/2.0/token - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - proxy: - base_url: https://api.smartsheet.com - docs: https://docs.nango.dev/integrations/all/smartsheet - -smugmug: - display_name: Smugmug - auth_mode: OAUTH1 - request_url: https://api.smugmug.com/services/oauth/1.0a/getRequestToken - authorization_url: https://api.smugmug.com/services/oauth/1.0a/authorize - token_url: https://api.smugmug.com/services/oauth/1.0a/getAccessToken - scope_separator: ',' - signature_method: 'PLAINTEXT' - proxy: - base_url: https://www.smugmug.com - docs: https://docs.nango.dev/integrations/all/smugmug - -snowflake: - display_name: Snowflake - categories: - - dev-tools - auth_mode: OAUTH2 - authorization_url: https://${connectionConfig.snowflake_account_url}/oauth/authorize - token_url: https://${connectionConfig.snowflake_account_url}/oauth/token-request - token_request_auth_method: basic - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://${connectionConfig.snowflake_account_url} - docs: https://docs.nango.dev/integrations/all/snowflake - connection_config: - snowflake_account_url: - type: string - title: Domain - description: The domain of your Snowflake account - format: hostname - prefix: https:// - -splitwise: - display_name: Splitwise - categories: - - payment - - social - auth_mode: OAUTH2 - authorization_url: https://secure.splitwise.com/oauth/authorize - token_url: https://secure.splitwise.com/oauth/token - proxy: - base_url: https://secure.splitwise.com - docs: https://docs.nango.dev/integrations/all/splitwise - -spotify: - display_name: Spotify - categories: - - other - auth_mode: OAUTH2 - authorization_url: https://accounts.spotify.com/authorize - token_url: https://accounts.spotify.com/api/token - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://api.spotify.com - docs: https://docs.nango.dev/integrations/all/spotify -spotify-oauth2-cc: - display_name: Spotify (custom) - categories: - - other - auth_mode: OAUTH2_CC - token_url: https://accounts.spotify.com/api/token - token_request_auth_method: basic - scope_separator: ' ' - token_params: - grant_type: client_credentials - proxy: - base_url: https://api.spotify.com - docs: https://docs.nango.dev/integrations/all/spotify - -squarespace: - display_name: Squarespace - categories: - - dev-tools - - design - auth_mode: OAUTH2 - authorization_url: https://login.squarespace.com/api/1/login/oauth/provider/authorize - token_url: https://login.squarespace.com/api/1/login/oauth/provider/tokens - token_request_auth_method: basic - scope_separator: ',' - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://api.squarespace.com - headers: - user-agent: ${connectionConfig.customappDescription} - docs: https://docs.nango.dev/integrations/all/squarespace - connection_config: - customappDescription: - type: string - title: User Agent - description: The user agent of your custom app - -squareup: - display_name: Squareup - categories: - - payment - auth_mode: OAUTH2 - authorization_url: https://connect.squareup.com/oauth2/authorize - token_url: https://connect.squareup.com/oauth2/token - disable_pkce: true - decode_url: true - authorization_params: - response_type: code - session: false - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://connect.squareup.com - docs: https://docs.nango.dev/integrations/all/squareup - -squareup-sandbox: - display_name: Squareup (sandbox) - auth_mode: OAUTH2 - authorization_url: https://connect.squareupsandbox.com/oauth2/authorize - token_url: https://connect.squareupsandbox.com/oauth2/token - disable_pkce: true - authorization_params: - response_type: code - session: false - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://connect.squareupsandbox.com - docs: https://docs.nango.dev/integrations/all/squareup - -stackexchange: - display_name: Stack Exchange - categories: - - knowledge-base - - support - auth_mode: OAUTH2 - authorization_url: https://stackoverflow.com/oauth - token_url: https://stackoverflow.com/oauth/access_token/json - default_scopes: - - no_expiry - proxy: - base_url: https://api.stackexchange.com - docs: https://docs.nango.dev/integrations/all/stackexchange - -strava: - display_name: Strava (mobile) - categories: - - social - - sports - auth_mode: OAUTH2 - authorization_url: https://www.strava.com/oauth/mobile/authorize - token_url: https://www.strava.com/api/v3/oauth/token - scope_separator: ',' - authorization_params: - response_type: code - approval_prompt: auto - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://www.strava.com - docs: https://docs.nango.dev/integrations/all/strava - -strava-web: - display_name: Strava (web) - categories: - - social - - sports - auth_mode: OAUTH2 - authorization_url: https://www.strava.com/oauth/authorize - token_url: https://www.strava.com/api/v3/oauth/token - scope_separator: ',' - authorization_params: - response_type: code - approval_prompt: force - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://www.strava.com - docs: https://docs.nango.dev/integrations/all/strava - -stripe: - display_name: Stripe - categories: - - payment - auth_mode: OAUTH2 - authorization_url: https://connect.stripe.com/oauth/authorize - token_url: https://connect.stripe.com/oauth/token - proxy: - base_url: https://api.stripe.com - docs: https://docs.nango.dev/integrations/all/stripe - -stripe-express: - display_name: Stripe Express - categories: - - payment - auth_mode: OAUTH2 - authorization_url: https://connect.stripe.com/express/oauth/authorize - token_url: https://connect.stripe.com/oauth/token - token_response_metadata: - - stripe_user_id - proxy: - base_url: https://api.stripe.com - docs: https://docs.nango.dev/integrations/all/stripe-express - -stripe-app: - display_name: Stripe App - categories: - - payment - auth_mode: OAUTH2 - authorization_url: https://marketplace.stripe.com/oauth/v2/authorize - token_url: https://api.stripe.com/v1/oauth/token - disable_pkce: true - proxy: - base_url: https://api.stripe.com - refresh_params: - grant_type: refresh_token - docs: https://docs.nango.dev/integrations/all/stripe-app - -stripe-app-sandbox: - display_name: Stripe App (sandbox) - auth_mode: OAUTH2 - authorization_url: https://marketplace.stripe.com/oauth/v2/${connectionConfig.appDomain}/authorize - token_url: https://api.stripe.com/v1/oauth/token - disable_pkce: true - proxy: - base_url: https://api.stripe.com - refresh_params: - grant_type: refresh_token - docs: https://docs.nango.dev/integrations/all/stripe-app - connection_config: - appDomain: - type: string - title: App Domain - description: The domain of your Stripe app - -survey-monkey: - display_name: SurveyMonkey - categories: - - surveys - auth_mode: OAUTH2 - authorization_url: https://api.surveymonkey.com/oauth/authorize - token_url: https://api.surveymonkey.com/oauth/token - disable_pkce: true - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - proxy: - base_url: https://api.surveymonkey.com - docs: https://docs.nango.dev/integrations/all/survey-monkey - -tapclicks: - display_name: TapClicks - auth_mode: OAUTH2_CC - categories: - - marketing - - analytics - token_url: https://api.tapclicks.com/oauth/accesstoken - token_params: - grant_type: client_credentials - proxy: - base_url: https://api.tapclicks.com/v2 - docs: https://docs.nango.dev/integrations/all/tapclicks - docs_connect: https://docs.nango.dev/integrations/all/tapclicks/connect - -tableau: - display_name: Tableau - categories: - - analytics - auth_mode: TABLEAU - token_url: https://${connectionConfig.myServer}/api/${connectionConfig.version}/auth/signin - proxy: - headers: - accept: application/json - content-type: application/json - base_url: https://${connectionConfig.myServer}/api/${connectionConfig.version} - docs: https://docs.nango.dev/integrations/all/tableau - connection_config: - myServer: - type: string - title: Domain - description: The domain of your Tableau instance - format: hostname - prefix: https:// - version: - type: string - title: API Version - description: The version of the Tableau API to use - -teamtailor: - display_name: Teamtailor - categories: - - ats - auth_mode: API_KEY - proxy: - base_url: https://${connectionConfig.extension}.teamtailor.com - retry: - after: 'x-rate-limit-reset' - headers: - authorization: Token token=${apiKey} - x-api-version: '20210218' - verification: - method: GET - endpoint: /v1/users - docs: https://docs.nango.dev/integrations/all/teamtailor - connection_config: - extension: - type: string - title: Teamtailor Domain - description: The subdomain of your Teamtailor instance - pattern: '^[a-z0-9_-]+$' - example: domain - suffix: .teamtailor.com - prefix: https:// - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Teamtailor account - -teamwork: - display_name: Teamwork - categories: - - productivity - - ticketing - auth_mode: OAUTH2 - authorization_url: https://www.teamwork.com/launchpad/login - token_url: https://www.teamwork.com/launchpad/v1/token.json - token_response_metadata: - - installation.apiEndPoint - proxy: - base_url: ${connectionConfig.installation.apiEndPoint} - docs: https://docs.nango.dev/integrations/all/teamwork - -ticktick: - display_name: TickTick - categories: - - productivity - - ticketing - auth_mode: OAUTH2 - authorization_url: https://ticktick.com/oauth/authorize - token_url: https://ticktick.com/oauth/token - scope_separator: ' ' - proxy: - base_url: https://api.ticktick.com - docs: https://docs.nango.dev/integrations/all/ticktick - -tiktok-accounts: - display_name: TikTok Accounts - categories: - - social - auth_mode: OAUTH2 - authorization_url: https://www.tiktok.com/v2/auth/authorize/ - token_url: https://business-api.tiktok.com/open_api/v1.3/tt_user/oauth2/token/ - refresh_url: https://business-api.tiktok.com/open_api/v1.3/tt_user/oauth2/refresh_token/ - proxy: - base_url: https://business-api.tiktok.com/open_api/v1.3/ - authorization_params: - response_type: code - authorization_url_replacements: - client_id: client_key - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - scope_separator: ',' - docs: https://docs.nango.dev/integrations/all/tiktok-accounts - -tiktok-ads: - display_name: TikTok Ads - categories: - - social - auth_mode: OAUTH2 - authorization_url: https://business-api.tiktok.com/portal/auth - token_url: https://business-api.tiktok.com/open_api/v1.3/oauth2/access_token/ - proxy: - base_url: https://business-api.tiktok.com/open_api/v1.3/ - headers: - access-token: ${accessToken} - token_params: - grant_type: authorization_code - authorization_url_replacements: - client_id: app_id - docs: https://docs.nango.dev/integrations/all/tiktok-ads - -timely: - display_name: Timely - categories: - - productivity - auth_mode: OAUTH2 - authorization_url: https://api.timelyapp.com/1.1/oauth/authorize - token_url: https://api.timelyapp.com/1.1/oauth/token - disable_pkce: true - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - proxy: - base_url: https://api.timelyapp.com - docs: https://docs.nango.dev/integrations/all/timely - -thrivecart-oauth: - display_name: ThriveCart (OAuth) - categories: - - e-commerce - - payment - auth_mode: OAUTH2 - authorization_url: https://thrivecart.com/authorization/new - token_url: https://thrivecart.com/authorization/token - scope_separator: ' ' - proxy: - base_url: https://thrivecart.com/api/external - docs: https://docs.nango.dev/integrations/all/thrivecart - -thrivecart-api-key: - display_name: ThriveCart (api key) - categories: - - e-commerce - - payment - auth_mode: API_KEY - proxy: - base_url: https://thrivecart.com/api/external - headers: - authorization: Bearer ${apiKey} - verification: - method: GET - endpoint: /ping - docs: https://docs.nango.dev/integrations/all/thrivecart - credentials: - apiKey: - type: string - title: API Key - description: The API key for your ThriveCart account - example: 'ASYDV5S8-0BSO1SH2-4BH5PO7U-YF8SV3CZ' - pattern: '^[A-Z0-9]{8}-[A-Z0-9]{10}-[A-Z0-9]{8}-[A-Z0-9]{8}$' - -tremendous: - display_name: Tremendous - categories: - - payment - auth_mode: OAUTH2 - authorization_url: https://api.tremendous.com/oauth/authorize - token_url: https://api.tremendous.com/oauth/token - scope_separator: ' ' - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://api.tremendous.com/api/v2 - docs: https://docs.nango.dev/integrations/all/tremendous - -tremendous-sandbox: - display_name: Tremendous (sandbox) - categories: - - payment - auth_mode: OAUTH2 - authorization_url: https://testflight.tremendous.com/oauth/authorize - token_url: https://testflight.tremendous.com/oauth/token - scope_separator: ' ' - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://testflight.tremendous.com/api/v2 - docs: https://docs.nango.dev/integrations/all/tremendous - -trello: - display_name: Trello - categories: - - productivity - - ticketing - auth_mode: OAUTH1 - request_url: https://trello.com/1/OAuthGetRequestToken - authorization_url: https://trello.com/1/OAuthAuthorizeToken - token_url: https://trello.com/1/OAuthGetAccessToken - signature_method: 'HMAC-SHA1' - scope_separator: ',' - authorization_params: - expiration: never - proxy: - base_url: https://api.trello.com - docs: https://docs.nango.dev/integrations/all/trello - -trello-scim: - display_name: Trello (SCIM API) - categories: - - productivity - - ticketing - auth_mode: API_KEY - proxy: - base_url: https://trello.com/scim - headers: - authorization: Bearer ${apiKey} - verification: - method: GET - endpoint: /v2/users?sortBy=displayName&count=10 - docs: https://docs.nango.dev/integrations/all/trello - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Trello scim account - doc_section: '#step-1-finding-your-trello-api-key' - -tsheetsteam: - display_name: TSheets - categories: - - hr - - productivity - auth_mode: OAUTH2 - authorization_url: https://rest.tsheets.com/api/v1/authorize - token_url: https://rest.tsheets.com/api/v1/grant - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://rest.tsheets.com/api/v1 - docs: https://docs.nango.dev/integrations/all/tsheetsteam - -todoist: - display_name: Todoist - categories: - - productivity - - ticketing - auth_mode: OAUTH2 - authorization_url: https://todoist.com/oauth/authorize - token_url: https://todoist.com/oauth/access_token - scope_separator: ',' - proxy: - base_url: https://api.todoist.com - docs: https://docs.nango.dev/integrations/all/todoist - -tumblr: - display_name: Tumblr - categories: - - social - - communication - auth_mode: OAUTH2 - authorization_url: https://www.tumblr.com/oauth2/authorize - token_url: https://api.tumblr.com/v2/oauth2/token - scope_separator: ' ' - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://api.tumblr.com/v2 - docs: https://docs.nango.dev/integrations/all/tumblr - -twitch: - display_name: Twitch - categories: - - gaming - - social - - sports - - video - auth_mode: OAUTH2 - authorization_url: https://id.twitch.tv/oauth2/authorize - token_url: https://id.twitch.tv/oauth2/token - authorization_params: - force_verify: false - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://api.twitch.tv - docs: https://docs.nango.dev/integrations/all/twitch - -twitter: - display_name: Twitter (v1) - categories: - - marketing - - social - auth_mode: OAUTH1 - request_url: https://api.twitter.com/oauth/request_token - authorization_url: https://api.twitter.com/oauth/authorize - token_url: https://api.twitter.com/oauth/access_token - signature_method: 'HMAC-SHA1' - request_params: - x_auth_access_type: write - proxy: - base_url: https://api.twitter.com - docs: https://docs.nango.dev/integrations/all/twitter -twitter-v2: - display_name: Twitter (v2) - categories: - - marketing - - social - auth_mode: OAUTH2 - authorization_url: https://twitter.com/i/oauth2/authorize - token_url: https://api.twitter.com/2/oauth2/token - token_request_auth_method: basic - authorization_params: - response_type: code - response_mode: query - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - default_scopes: - - offline.access - proxy: - base_url: https://api.twitter.com - docs: https://docs.nango.dev/integrations/all/twitter -twitter-oauth2-cc: - display_name: Twitter (custom) - categories: - - marketing - - social - auth_mode: OAUTH2_CC - token_url: https://api.twitter.com/oauth2/token - token_request_auth_method: basic - scope_separator: ' ' - token_params: - grant_type: client_credentials - proxy: - base_url: https://api.twitter.com - docs: https://docs.nango.dev/integrations/all/twitter - -twinfield: - display_name: Twinfield - auth_mode: OAUTH2 - authorization_url: https://login.twinfield.com/auth/authentication/connect/authorize - token_url: https://login.twinfield.com/auth/authentication/connect/token - authorization_params: - response_type: code - nonce: AnotherRandomStringTwinfield - refresh_params: - grant_type: refresh_token - scope_separator: ' ' - default_scopes: - - openid - - twf.user - - twf.organisation - - twf.organisationUser - - offline_access - disable_pkce: true - proxy: - base_url: https://${connectionConfig.cluster}.twinfield.com - docs: https://docs.nango.dev/integrations/all/twinfield - connection_config: - cluster: - type: string - title: Twinfield Cluster - description: The cluster to your Twinfield instance - pattern: '^[a-z0-9_-]+$' - example: accounting - suffix: .twinfield.com - prefix: https:// - -twenty-crm: - display_name: Twenty CRM - categories: - - crm - auth_mode: API_KEY - proxy: - base_url: https://api.twenty.com/rest - headers: - authorization: Bearer ${apiKey} - retry: - after: 'retry-after' - verification: - method: GET - endpoint: /companies - docs: https://docs.nango.dev/integrations/all/twenty-crm - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Twenty CRM account - example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIyMTIxMjEyMS0yNmExLTRkODktYjQ2YS0wNDI0NTViODM3N2YiLCJ0eXBlIjoiQVBJX0tFWSIsIndvcmtzcGFjZUlkIjoiMjEyMTIxMjEtMjZhMS00ZDg5LWI0NmEtMDQyNDU1YjgzNzdmIiwiaWF0IjoxNzMxMzA5MzQwLCJleHAiOjQ4ODQ5MDU3MzksImp0aSI6ImVmZTg4MjcxLTM4OWItNDk5Mi04MjYwLWZjNGIxZmYxYjRiMSJ9.n3tohFIEBBRMsyas_agbh3-KvKXYUnjyhrYzTHYC3vc' - pattern: '^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$' - -twenty-crm-self-hosted: - display_name: Twenty CRM (Self Hosted) - categories: - - crm - auth_mode: API_KEY - proxy: - base_url: https://${connectionConfig.domain}/rest - headers: - authorization: Bearer ${apiKey} - retry: - after: 'retry-after' - verification: - method: GET - endpoint: /companies - docs: https://docs.nango.dev/integrations/all/twenty-crm - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Twenty CRM account - example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIyMTIxMjEyMS0yNmExLTRkODktYjQ2YS0wNDI0NTViODM3N2YiLCJ0eXBlIjoiQVBJX0tFWSIsIndvcmtzcGFjZUlkIjoiMjEyMTIxMjEtMjZhMS00ZDg5LWI0NmEtMDQyNDU1YjgzNzdmIiwiaWF0IjoxNzMxMzA5MzQwLCJleHAiOjQ4ODQ5MDU3MzksImp0aSI6ImVmZTg4MjcxLTM4OWItNDk5Mi04MjYwLWZjNGIxZmYxYjRiMSJ9.n3tohFIEBBRMsyas_agbh3-KvKXYUnjyhrYzTHYC3vc' - pattern: '^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$' - connection_config: - domain: - type: string - title: Twenty CRM domain - description: The domain of your Twnety CRM instance - pattern: '^[A-Za-z0-9.-]+\.[A-Za-z]{2,}$' - example: domain - -typeform: - display_name: Typeform - categories: - - surveys - auth_mode: OAUTH2 - authorization_url: https://api.typeform.com/oauth/authorize - token_url: https://api.typeform.com/oauth/token - disable_pkce: true - default_scopes: - - offline - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://api.typeform.com - docs: https://docs.nango.dev/integrations/all/typeform - -typefully: - display_name: Typefully - categories: - - analytics - - communication - - social - auth_mode: API_KEY - proxy: - base_url: https://api.typefully.com - headers: - x-api-key: Bearer ${apiKey} - verification: - method: GET - endpoint: /v1/notifications/ - docs: https://docs.nango.dev/integrations/all/typefully - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Typefully account - -uber: - display_name: Uber - auth_mode: OAUTH2 - authorization_url: https://login.uber.com/oauth/v2/authorize - token_url: https://login.uber.com/oauth/v2/token - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://api.uber.com - docs: https://docs.nango.dev/integrations/all/uber - -unanet: - display_name: Unanet - categories: - - crm - - erp - - accounting - auth_mode: BASIC - proxy: - headers: - x-compass-firm-id: ${connectionConfig.firmId} - x-compass-api-key: ${connectionConfig.apiKey} - base_url: https://compass.cosential.com - verification: - method: GET - endpoint: /api/projects - docs: https://docs.nango.dev/integrations/all/unanet - docs_connect: https://docs.nango.dev/integrations/all/unanet/connect - connection_config: - firmId: - type: string - title: Firm ID - description: The firm ID of your Unanet instance - doc_section: '#step-2-finding-the-firm-id' - apiKey: - type: string - title: API Key - description: The API key of your Unanet instance - secret: true - doc_section: '#step-3-finding-the-api-key' - credentials: - username: - type: string - title: User name - description: Your Unanet username - doc_section: '#step-1-finding-username-and-password' - password: - type: string - title: Password - description: Your Unanet password - default_value: '' - doc_section: '#step-1-finding-username-and-password' - -unauthenticated: - display_name: Unauthenticated - auth_mode: NONE - webhook_routing_script: unauthenticatedWebhookRouting - docs: https://docs.nango.dev/integrations/all/unauthenticated - -unipile: - display_name: Unipile - categories: - - crm - - marketing - auth_mode: API_KEY - proxy: - base_url: https://${connectionConfig.subdomain}.unipile.com:${connectionConfig.port} - headers: - x-api-key: ${apiKey} - verification: - method: GET - endpoint: /api/v1/contacts - docs: https://docs.nango.dev/integrations/all/unipile - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Unipile instance - connection_config: - subdomain: - type: string - title: Subdomain - description: The subdomain of your Unipile instance - pattern: '^[a-z0-9_-]+$' - example: api1 - suffix: .unipile.com - prefix: https:// - port: - type: string - title: Port - description: The port of your Unipile instance - pattern: '^[0-9]+$' - example: '13113' - -vimeo: - display_name: Vimeo - categories: - - video - auth_mode: OAUTH2 - authorization_url: https://api.vimeo.com/oauth/authorize - token_url: https://api.vimeo.com/oauth/access_token - token_request_auth_method: basic - scope_separator: ' ' - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - proxy: - base_url: https://api.vimeo.com - docs: https://docs.nango.dev/integrations/all/vimeo - -vimeo-basic: - display_name: Vimeo (basic auth) - categories: - - video - auth_mode: BASIC - proxy: - base_url: https://api.vimeo.com - verification: - method: GET - endpoint: / - docs: https://docs.nango.dev/integrations/all/vimeo - -wakatime: - display_name: Wakatime - categories: - - analytics - - dev-tools - auth_mode: OAUTH2 - authorization_url: https://wakatime.com/oauth/authorize - token_url: https://wakatime.com/oauth/token - proxy: - base_url: https://wakatime.com - docs: https://docs.nango.dev/integrations/all/wakatime - -wave-accounting: - display_name: Wave Accounting - categories: - - accounting - auth_mode: OAUTH2 - authorization_url: https://api.waveapps.com/oauth2/authorize - token_url: https://api.waveapps.com/oauth2/token/ - proxy: - base_url: https://gql.waveapps.com - docs: https://docs.nango.dev/integrations/all/wave-accounting - -wealthbox: - display_name: Wealthbox - categories: - - crm - auth_mode: OAUTH2 - authorization_url: https://app.crmworkspace.com/oauth/authorize - token_url: https://app.crmworkspace.com/oauth/token - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://api.crmworkspace.com - docs: https://docs.nango.dev/integrations/all/wealthbox - -webflow: - display_name: Webflow - categories: - - dev-tools - - design - - cms - auth_mode: OAUTH2 - authorization_url: https://webflow.com/oauth/authorize - token_url: https://api.webflow.com/oauth/access_token - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - proxy: - base_url: https://api.webflow.com - docs: https://docs.nango.dev/integrations/all/webflow - -whatsapp-business: - display_name: WhatsApp Business - categories: - - communication - - marketing - auth_mode: API_KEY - proxy: - headers: - authorization: Bearer ${apiKey} - content-type: application/json - base_url: https://graph.facebook.com - verification: - endpoint: /v21.0/me - method: GET - docs: https://docs.nango.dev/integrations/all/whatsapp-business - credentials: - apiKey: - type: string - title: API Key - description: The access token to your whatsapp account - pattern: '^[a-zA-Z0-9]+$' - -whoop: - display_name: Whoop - categories: - - sports - auth_mode: OAUTH2 - authorization_url: https://api.prod.whoop.com/oauth/oauth2/auth - token_url: https://api.prod.whoop.com/oauth/oauth2/token - authorization_params: - response_type: code - proxy: - base_url: https://api.prod.whoop.com/ - retry: - after: 'x-ratelimit-reset' - paginate: - type: cursor - offset_name_in_request: nextToken - limit_name_in_request: limit - docs: https://docs.nango.dev/integrations/all/whoop - -wildix-pbx: - display_name: Wildix PBX - auth_mode: OAUTH2 - authorization_url: https://${connectionConfig.subdomain}.wildixin.com/authorization/oauth2 - token_url: https://${connectionConfig.subdomain}.wildixin.com/authorization/oauth2Token - authorization_params: - response_type: code - redirect_uri_metadata: - - subdomain - docs: https://docs.nango.dev/integrations/all/wildix-pbx - proxy: - base_url: https://${connectionConfig.subdomain}.wildixin.com - connection_config: - subdomain: - type: string - title: Wildix Domain - description: The subdomain of your Wildix instance - pattern: '^[a-z0-9_-]+$' - example: domain - suffix: .wildixin.com - prefix: https:// - -wordpress: - display_name: WordPress - categories: - - dev-tools - - design - - cms - auth_mode: OAUTH2 - authorization_url: https://public-api.wordpress.com/oauth2/authorize - token_url: https://public-api.wordpress.com/oauth2/token - scope_separator: ' ' - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - proxy: - base_url: https://public-api.wordpress.com/rest/v1 - docs: https://docs.nango.dev/integrations/all/wordpress - -woocommerce: - display_name: WooCommerce - categories: - - e-commerce - - dev-tools - - design - auth_mode: BASIC - proxy: - base_url: https://${connectionConfig.storeURL} - verification: - method: GET - endpoint: /wp-json/wc/v3/customers - docs: https://docs.nango.dev/integrations/all/woocommerce - docs_connect: https://docs.nango.dev/integrations/all/woocommerce/connect - connection_config: - storeURL: - type: string - title: Domain - description: The domain of your WooCommerce store - credentials: - username: - type: string - title: User name - description: Your woocommerce Consumer Key - doc_section: '#step-1-finding-your-woocommerce-consumer-key' - password: - type: string - title: Password - description: Your woocommerce Consumer Secret - default_value: '' - doc_section: '#step-2-finding-your-woocommerce-consumer-secret' - -workable: - display_name: Workable - categories: - - ats - auth_mode: API_KEY - proxy: - headers: - authorization: Bearer ${apiKey} - base_url: https://${connectionConfig.subdomain}.workable.com - retry: - at: 'x-rate-limit-reset' - post_connection_script: workablePostConnection - docs: https://docs.nango.dev/integrations/all/workable - docs_connect: https://docs.nango.dev/integrations/all/workable/connect - connection_config: - subdomain: - type: string - title: Workable Domain - description: The subdomain of your Workable account - pattern: '^[a-z0-9_-]+$' - example: domain - suffix: .workable.com - prefix: https:// - optional: true - credentials: - apiKey: - type: string - title: API Key - description: The API key for your Workable account - doc_section: '#step-1-finding-workable-api-key' - -workable-oauth: - display_name: Workable (OAuth) - categories: - - ats - auth_mode: OAUTH2 - authorization_url: https://www.workable.com/oauth/authorize - token_url: https://www.workable.com/oauth/token - scope_separator: '+' - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://${connectionConfig.subdomain}.workable.com - retry: - at: 'x-rate-limit-reset' - docs: https://docs.nango.dev/integrations/all/workable - connection_config: - subdomain: - type: string - title: Workable Domain - description: The subdomain of your Workable account - pattern: '^[a-z0-9_-]+$' - example: domain - suffix: .workable.com - prefix: https:// - -workday: - display_name: Workday - categories: - - hr - auth_mode: BASIC - proxy: - base_url: https://${connectionConfig.subdomain}.workday.com - docs: https://docs.nango.dev/integrations/all/workday - docs_connect: https://docs.nango.dev/integrations/all/workday/connect - connection_config: - subdomain: - type: string - title: Workday Domain - description: The subdomain of your Workday account - pattern: '^[a-z0-9_-]+$' - example: domain - suffix: .workday.com - prefix: https:// - credentials: - username: - type: string - title: Client ID - description: Workday Client ID - doc_section: '#step-2-find-your-workday-client-id-and-client-secret' - password: - type: string - title: Client Secret - description: Workday Client Secret - doc_section: '#step-2-find-your-workday-client-id-and-client-secret' - # https://community.workday.com/sites/default/files/file-hosting/productionapi/index.html - # Workday is using basic auth with client ID and client secret as username and password - -wrike: - display_name: Wrike - categories: - - productivity - auth_mode: OAUTH2 - authorization_url: https://login.wrike.com/oauth2/authorize/v4 - token_url: https://login.wrike.com/oauth2/token - scope_separator: ',' - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - token_response_metadata: - - host - proxy: - base_url: https://${connectionConfig.host}/api/v4 - docs: https://docs.nango.dev/integrations/all/wrike - connection_config: - host: - type: string - title: Domain - description: The domain of your Wrike account - format: hostname - prefix: https:// - -xero: - display_name: Xero - categories: - - accounting - auth_mode: OAUTH2 - authorization_url: https://login.xero.com/identity/connect/authorize - token_url: https://identity.xero.com/connect/token - authorization_params: - response_type: code - default_scopes: - - offline_access - - openid - proxy: - base_url: https://api.xero.com - retry: - after: 'retry-after' - post_connection_script: xeroPostConnection - docs: https://docs.nango.dev/integrations/all/xero - -yahoo: - display_name: Yahoo - categories: - - social - auth_mode: OAUTH2 - authorization_url: https://api.login.yahoo.com/oauth2/request_auth - token_url: https://api.login.yahoo.com/oauth2/get_token - proxy: - base_url: https://${connectionConfig.apiDomain} - docs: https://docs.nango.dev/integrations/all/yahoo - connection_config: - apiDomain: - type: string - title: API Domain - description: The domain to the API you want to connect to - format: hostname - example: fantasysports.yahooapis.com - prefix: https:// - -yandex: - display_name: Yandex - categories: - - social - auth_mode: OAUTH2 - authorization_url: https://oauth.yandex.com/authorize - token_url: https://oauth.yandex.com/token - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://translate.yandex.net - docs: https://docs.nango.dev/integrations/all/yandex - -youtube: - display_name: YouTube - alias: google - categories: - - video - docs: https://docs.nango.dev/integrations/all/youtube - -zapier: - display_name: Zapier - categories: - - dev-tools - auth_mode: OAUTH2 - authorization_url: https://api.zapier.com/v2/authorize - token_url: https://zapier.com/oauth/token - scope_separator: ' ' - default_scopes: - - authentication - - authentication:write - - profile - - zap - - zap:write - proxy: - base_url: https://api.zapier.com - authorization_params: - response_type: code - response_mode: query - state: N@nG0s%rinG - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - docs: https://docs.nango.dev/integrations/all/zapier - -zapier-nla: - display_name: Zapier NLA - auth_mode: OAUTH2 - authorization_url: https://nla.zapier.com/oauth/authorize/ - token_url: https://nla.zapier.com/oauth/token/ - proxy: - base_url: https://nla.zapier.com - docs: https://docs.nango.dev/integrations/all/zapier-nla - -zendesk: - display_name: Zendesk - categories: - - support - - ticketing - auth_mode: OAUTH2 - authorization_url: https://${connectionConfig.subdomain}.zendesk.com/oauth/authorizations/new - token_url: https://${connectionConfig.subdomain}.zendesk.com/oauth/tokens - proxy: - base_url: https://${connectionConfig.subdomain}.zendesk.com - retry: - after: 'retry-after' - paginate: - type: link - limit_name_in_request: per_page - link_path_in_response_body: next_page - docs: https://docs.nango.dev/integrations/all/zendesk - docs_connect: https://docs.nango.dev/integrations/all/zendesk/connect - connection_config: - subdomain: - type: string - title: Zendesk Domain - description: The subdomain of your Zendesk account - pattern: '^[a-z0-9_-]+$' - example: domain - suffix: .zendesk.com - prefix: https:// - doc_section: '#step-1-finding-your-subdomain' - -zenefits: - display_name: Zenefits - categories: - - hr - auth_mode: OAUTH2 - authorization_url: https://secure.zenefits.com/oauth2/platform-authorize - token_url: https://secure.zenefits.com/oauth2/token - authorization_params: - response_type: code - token_params: - grant_type: authorization_code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://api.zenefits.com - docs: https://docs.nango.dev/integrations/all/zenefits - -zoho: - display_name: Zoho - categories: - - accounting - auth_mode: OAUTH2 - authorization_url: https://accounts.zoho.${connectionConfig.extension}/oauth/v2/auth - token_url: https://accounts.zoho.${connectionConfig.extension}/oauth/v2/token - authorization_params: - prompt: consent - access_type: offline - proxy: - base_url: https://www.zohoapis.${connectionConfig.extension} - paginate: - type: offset - response_path: data - offset_name_in_request: page - limit_name_in_request: per_page - docs: https://docs.nango.dev/integrations/all/zoho - connection_config: - extension: - type: string - title: Domain Extension - description: The domain extension of your Zoho account - pattern: '^[a-z.]+$' - prefix: https://accounts.zoho. - example: com - suffix: / - -zoho-books: - display_name: Zoho Books - alias: zoho - docs: https://docs.nango.dev/integrations/all/zoho-books - -zoho-crm: - display_name: Zoho CRM - alias: zoho - docs: https://docs.nango.dev/integrations/all/zoho-crm - -zoho-desk: - display_name: Zoho Desk - categories: - - support - - ticketing - alias: zoho - docs: https://docs.nango.dev/integrations/all/zoho-desk - -zoho-inventory: - display_name: Zoho Inventory - categories: - - e-commerce - alias: zoho - docs: https://docs.nango.dev/integrations/all/zoho-inventory - -zoho-invoice: - display_name: Zoho Invoice - categories: - - invoicing - alias: zoho - docs: https://docs.nango.dev/integrations/all/zoho-invoice - -zoho-mail: - display_name: Zoho Mail - categories: - - productivity - - communication - alias: zoho - proxy: - base_url: https://mail.zoho.${connectionConfig.extension} - docs: https://docs.nango.dev/integrations/all/zoho-mail - connection_config: - extension: - type: string - title: Domain Extension - description: The domain extension of your Zoho account - pattern: '^[a-z.]+$' - -zoho-bigin: - display_name: Zoho Bigin - alias: zoho - docs: https://docs.nango.dev/integrations/all/zoho-bigin - -zoho-people: - display_name: Zoho People - categories: - - hr - alias: zoho - proxy: - base_url: https://people.zoho.com - docs: https://docs.nango.dev/integrations/all/zoho-people - -zoom: - display_name: Zoom - categories: - - video - auth_mode: OAUTH2 - authorization_url: https://zoom.us/oauth/authorize - token_url: https://zoom.us/oauth/token - scope_separator: ',' - authorization_params: - response_type: code - refresh_params: - grant_type: refresh_token - proxy: - base_url: https://api.zoom.us/v2 - paginate: - type: cursor - cursor_path_in_response: next_page_token - cursor_name_in_request: next_page_token - limit_name_in_request: page_size - docs: https://docs.nango.dev/integrations/all/zoom - -zoominfo: - display_name: ZoomInfo - categories: - - crm - - marketing - auth_mode: OAUTH2_CC - proxy: - retry: - after: 'x-ratelimit-reset' - base_url: https://api.zoominfo.com - token_url: https://api.zoominfo.com/authenticate - token_request_auth_method: custom - body_format: json - docs: https://docs.nango.dev/integrations/all/zoominfo - docs_connect: https://docs.nango.dev/integrations/all/zoominfo/connect diff --git a/packages/shared/tsconfig.json b/packages/shared/tsconfig.json index 048d5c81bb6..b523eaffc1f 100644 --- a/packages/shared/tsconfig.json +++ b/packages/shared/tsconfig.json @@ -14,9 +14,6 @@ { "path": "../nango-yaml" }, - { - "path": "../node-client" - }, { "path": "../types" }, @@ -31,6 +28,9 @@ }, { "path": "../orchestrator" + }, + { + "path": "../providers" } ], "include": ["lib/**/*", "../utils/lib/vitest.d.ts"] diff --git a/scripts/docs-gen-snippets.ts b/scripts/docs-gen-snippets.ts index f0b0a7d6963..f3421bd98c6 100644 --- a/scripts/docs-gen-snippets.ts +++ b/scripts/docs-gen-snippets.ts @@ -18,7 +18,7 @@ const prettyAuthModes: Record = { }; const flowsPath = 'packages/shared/flows.yaml'; -const providersPath = 'packages/shared/providers.yaml'; +const providersPath = 'packages/providers/providers.yaml'; const docsPath = 'docs-v2/integrations/all'; const snippetsPath = 'docs-v2/snippets/generated'; @@ -153,9 +153,9 @@ function useCasesSnippet(useCases: any) { return ` ## Pre-built integrations - + - + ${Object.values(sortedGroups) .map( (group) => ` @@ -185,7 +185,7 @@ function emptyUseCases() { return `## Pre-built integrations _No pre-built integration yet (time to contribute: <48h)_ - + Not seeing the integration you need? [Build your own](https://docs.nango.dev/guides/custom-integration-builder/overview) independently. ` .split('\n') diff --git a/scripts/publish.sh b/scripts/publish.sh index 287f21bf515..ed72bd44195 100755 --- a/scripts/publish.sh +++ b/scripts/publish.sh @@ -51,67 +51,31 @@ popd npm ci npm run ts-build -# pack shared dependencies -mkdir -p "$GIT_ROOT_DIR/packages/shared/vendor" -mkdir -p "$GIT_ROOT_DIR/packages/database/vendor" -pushd "$GIT_ROOT_DIR/packages/utils" -jq '.bundleDependencies = true' package.json >temp.json && mv temp.json package.json -npm install --workspaces=false -npm pack --pack-destination "$GIT_ROOT_DIR/packages/shared/vendor" -cp "$GIT_ROOT_DIR/packages/shared/vendor/nangohq-utils-1.0.0.tgz" "$GIT_ROOT_DIR/packages/database/vendor" -popd -pushd "$GIT_ROOT_DIR/packages/shared" -npm install "@nangohq/utils@file:vendor/nangohq-utils-1.0.0.tgz" --workspaces=false -popd - -pushd "$GIT_ROOT_DIR/packages/database" -jq '.bundleDependencies = true' package.json >temp.json && mv temp.json package.json -npm install "@nangohq/utils@file:vendor/nangohq-utils-1.0.0.tgz" --workspaces=false -npm install --workspaces=false -npm pack --pack-destination "$GIT_ROOT_DIR/packages/shared/vendor" -popd -pushd "$GIT_ROOT_DIR/packages/shared" -npm install "@nangohq/database@file:vendor/nangohq-database-1.0.0.tgz" -popd - -pushd "$GIT_ROOT_DIR/packages/utils" -jq 'del(.bundleDependencies)' package.json >temp.json && mv temp.json package.json -popd - -pushd "$GIT_ROOT_DIR/packages/database" -jq 'del(.bundleDependencies)' package.json >temp.json && mv temp.json package.json -popd - # Types bump_and_npm_publish "@nangohq/types" "$VERSION" bump_other_pkg "cli" "types" bump_other_pkg "frontend" "types" bump_other_pkg "nango-yaml" "types" bump_other_pkg "node-client" "types" -bump_other_pkg "shared" "types" bump_other_pkg "runner-sdk" "types" bump_other_pkg "providers" "types" # NangoYaml bump_and_npm_publish "@nangohq/nango-yaml" "$VERSION" bump_other_pkg "cli" "nango-yaml" -bump_other_pkg "shared" "nango-yaml" + +# Providers +bump_and_npm_publish "@nangohq/providers" "$VERSION" +bump_other_pkg "runner-sdk" "providers" # Node client bump_and_npm_publish "@nangohq/node" "$VERSION" -pushd "$GIT_ROOT_DIR/packages/shared" -npm install @nangohq/node@$VERSION -popd +bump_other_pkg "runner-sdk" "node" +bump_other_pkg "cli" "node" -# Shared -bump_and_npm_publish "@nangohq/shared" "$VERSION" -# Update all packages to use the new shared version -package_dirs=("cli") -for dir in "${package_dirs[@]}"; do - pushd "$GIT_ROOT_DIR/packages/$dir" - npm install @nangohq/shared@^$VERSION - popd -done +# Runner SDK +bump_and_npm_publish "@nangohq/runner-sdk" "$VERSION" +bump_other_pkg "cli" "runner-sdk" # CLI bump_and_npm_publish "nango" "$VERSION" @@ -122,18 +86,6 @@ pushd "$GIT_ROOT_DIR/packages/webapp" npm install @nangohq/frontend@$VERSION popd -# clean up -rm packages/shared/package-lock.json -rm packages/utils/package-lock.json -rm packages/database/package-lock.json -pushd "$GIT_ROOT_DIR/packages/shared" -npm install "@nangohq/utils@file:../utils" -npm install "@nangohq/database@file:../database" -popd -pushd "$GIT_ROOT_DIR/packages/database" -npm install "@nangohq/utils@file:../utils" -popd - jq ".version = \"$VERSION\"" package.json >temp.json && mv temp.json package.json npm i diff --git a/scripts/validation/providers/validate.ts b/scripts/validation/providers/validate.ts index 07aed790200..64dd5243b51 100644 --- a/scripts/validation/providers/validate.ts +++ b/scripts/validation/providers/validate.ts @@ -19,7 +19,7 @@ const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const pathSchema = path.join(__dirname, 'schema.json'); -const pathProviders = path.join(__dirname, '../../../packages/shared/providers.yaml'); +const pathProviders = path.join(__dirname, '../../../packages/providers/providers.yaml'); // Schema const ajv = new Ajv({ allErrors: true, discriminator: true }); diff --git a/scripts/webflow-api-sync.ts b/scripts/webflow-api-sync.ts index 27fc0c10591..ce317a271b6 100644 --- a/scripts/webflow-api-sync.ts +++ b/scripts/webflow-api-sync.ts @@ -20,8 +20,8 @@ if (!process.env['WEBFLOW_CMS_API_TOKEN']) { const webflow = new WebflowClient({ accessToken: process.env['WEBFLOW_CMS_API_TOKEN'] }); -const providersPath = 'packages/shared/providers.yaml'; -// eslint-disable-next-line import/no-named-as-default-member, @typescript-eslint/no-explicit-any +const providersPath = 'packages/providers/providers.yaml'; +// eslint-disable-next-line import/no-named-as-default-member const providers = yaml.load(await fs.readFile(providersPath, 'utf8')) as Record; const docsPath = 'docs-v2/integrations/all';