Skip to content

Comments

Hubspot: get-company-by-domain#424

Open
bastienbeurier wants to merge 1 commit intomainfrom
bastien/hubspot/get-company-by-domain
Open

Hubspot: get-company-by-domain#424
bastienbeurier wants to merge 1 commit intomainfrom
bastien/hubspot/get-company-by-domain

Conversation

@bastienbeurier
Copy link
Member

Describe your changes

Issue ticket number and link

Checklist before requesting a review (skip if just adding/editing APIs & templates)

  • I added tests, otherwise the reason is:
  • External API requests have retries
  • Pagination is used where appropriate
  • The built in nango.paginate call is used instead of a while (true) loop
  • Third party requests are NOT parallelized (this can cause issues with rate limits)
  • If a sync requires metadata the nango.yaml has auto_start: false
  • If the sync is a full sync then track_deletes: true is set
  • I followed the best practices and guidelines from the Writing Integration Scripts doc

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 15, 2025

Note

.coderabbit.yaml has unrecognized properties

CodeRabbit is using all valid settings from your configuration. Unrecognized properties (listed below) have been ignored and may indicate typos or deprecated fields that can be removed.

⚠️ Parsing warnings (1)
Validation error: Unrecognized key(s) in object: 'auto_resolve_threads'
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Walkthrough

This PR introduces a new HubSpot action "get-company-by-domain" for querying companies by domain name. It adds action metadata in nango.json, defines TypeScript input/output interfaces and zod schemas, implements the action handler using HubSpot's CRM v3 search endpoint, provides mock HTTP responses and test data, includes a Vitest test case, and updates package.json with a nango version downgrade (0.69.18 → 0.69.14) and a new soap dependency (v1.6.1).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Package.json downgrade: Review the nango version downgrade from 0.69.18 to 0.69.14—verify whether this is intentional or indicates a compatibility issue requiring documentation.
  • New soap dependency: Confirm the purpose of adding soap v1.6.1 and ensure it's necessary for this action or a related change.
  • API integration logic: Verify the HubSpot CRM v3 search endpoint implementation, retry logic, field mapping, and error handling in get-company-by-domain.ts.
  • Schema consistency: Cross-check input/output interfaces across nango.json, schema.json, and schema.ts for alignment.
  • Mock HTTP response: Validate the mocked request/response structure matches actual HubSpot API behavior.

Possibly related PRs

Suggested reviewers

  • khaliqgant
  • hassan254-prog

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Description check ⚠️ Warning The description is entirely empty—all required sections lack content, and all checklist items remain unchecked. Fill in the 'Describe your changes' and 'Issue ticket number and link' sections with substantive information, and verify or check relevant checklist items based on implementation details.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding a new HubSpot action to fetch companies by domain.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch bastien/hubspot/get-company-by-domain

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@my-senior-dev-pr-review
Copy link

🤖 My Senior Dev

11 files reviewed • 3 need attention

⚠️ Needs Attention:

  • integrations/.nango/nango.json — New action endpoint for fetching company information could impact authentication and requires proper permission checks.

View full analysis →


💬 Try: @my-senior-dev explain this change or summon @chaos-monkey 🐵 @security-auditor 🔒 @optimizer ⚡ for different perspectives

📖 All commands & personas

You can interact with me by mentioning @my-senior-dev in any comment:

In PR comments or on any line of code:

  • Ask questions about the code or PR
  • Request explanations of specific changes
  • Get suggestions for improvements

Slash commands:

  • /help — Show all available commands
  • /archeology — See the history and evolution of changed files
  • /profile — Performance analysis and suggestions
  • /expertise — Find who knows this code best
  • /personas — List all available AI personas

AI Personas (mention to get their perspective):

Persona Focus
@chaos-monkey 🐵 Edge cases & failure scenarios
@skeptic 🤨 Challenge assumptions
@optimizer Performance & efficiency
@security-auditor 🔒 Security vulnerabilities
@accessibility-advocate Inclusive design
@junior-dev 🌱 Simple explanations
@tech-debt-collector 💳 Code quality & shortcuts
@ux-champion 🎨 User experience
@devops-engineer 🚀 Deployment & scaling
@documentation-nazi 📚 Documentation gaps
@legacy-whisperer 🏛️ Working with existing code
@test-driven-purist Testing & TDD

For the best experience, view this PR on myseniordev.com — includes AI chat, file annotations, and interactive reviews.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
integrations/.nango/nango.json (1)

5805-5825: Align HubSpot scopes (and optionally path naming) with existing actions

The action wiring looks structurally correct, but two small consistency points:

  • Other HubSpot company read flows (e.g., the companies sync) list both "crm.objects.companies.read" and "oauth" in scopes. Here you only include the granular scope. For consistency with the rest of the HubSpot config and to better document required permissions, consider adding "oauth" as well.
  • Nit: most company endpoints here use plural "/companies" while this action uses "/company/search". If there isn’t a strong reason to diverge, you might want to align the path naming with the existing pattern for easier discoverability.
integrations/hubspot/tests/hubspot-get-company-by-domain.test.ts (1)

1-19: Happy-path test is solid; consider a not-found case later

This test correctly exercises the action against the Nango mock harness and validates the expected output. If you want stronger coverage later, you could add a second test for the “no company found” scenario.

integrations/.nango/schema.ts (1)

5417-5425: New HubSpot get-company-by-domain action types look correct; consider naming consistency

The input/output shapes are minimal and coherent (domain in, name/domain/created_at out) and match the general HubSpot action patterns in this file.

If you want tighter internal consistency with other HubSpot company models here (Company, ActionOutput_hubspot_createcompany, etc.), consider renaming created_at to created_date unless you explicitly prefer mirroring HubSpot’s createdAt field.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between abbf6b3 and 3414844.

⛔ Files ignored due to path filters (1)
  • integrations/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (10)
  • integrations/.nango/nango.json (1 hunks)
  • integrations/.nango/schema.json (2 hunks)
  • integrations/.nango/schema.ts (2 hunks)
  • integrations/hubspot/actions/get-company-by-domain.ts (1 hunks)
  • integrations/hubspot/mocks/get-company-by-domain/input.json (1 hunks)
  • integrations/hubspot/mocks/get-company-by-domain/output.json (1 hunks)
  • integrations/hubspot/mocks/nango/post/proxy/crm/v3/objects/companies/search/get-company-by-domain/21ca0bdc7ba4b2bed957f428e1b3ceb43e07bced.json (1 hunks)
  • integrations/hubspot/tests/hubspot-get-company-by-domain.test.ts (1 hunks)
  • integrations/index.ts (1 hunks)
  • integrations/package.json (1 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/typescript-development-guidelines-shortcuts.mdc)

**/*.{ts,tsx}: Classes must use PascalCase naming convention
Variables, functions, and methods must use camelCase naming convention
Files and directories must use kebab-case naming convention
Use descriptive names for functions, combining verbs and nouns (e.g., getUserData)
Prefer arrow functions for simple operations
Use default parameters and object destructuring in functions
Document all code (classes, functions, methods, fields, types, interfaces) with JSDoc using only TypeDoc compatible tags
When writing JSDocs, only use TypeDoc compatible tags
For any new types, prefer to create a Zod schema and a Zod inference type for the created schema
Create custom types/interfaces for complex structures
Use 'readonly' for immutable properties
If an import is only used as a type in the file, use 'import type' instead of 'import'
Utilize Lodash, 'Promise.all()', and other standard techniques to optimize performance when working with large datasets
Always write JSDocs for all code: classes, functions, methods, fields, types, interfaces
Use strong typing and avoid 'any'
Ensure proper typing
Review naming conventions

Files:

  • integrations/hubspot/actions/get-company-by-domain.ts
  • integrations/hubspot/tests/hubspot-get-company-by-domain.test.ts
  • integrations/index.ts
**/*.{ts,tsx,env}

📄 CodeRabbit inference engine (.cursor/rules/typescript-development-guidelines-shortcuts.mdc)

Constants and environment variables must use UPPERCASE naming convention

Files:

  • integrations/hubspot/actions/get-company-by-domain.ts
  • integrations/hubspot/tests/hubspot-get-company-by-domain.test.ts
  • integrations/index.ts
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/nango-script-best-practices.mdc)

**/*.ts: In full syncs (syncType: 'full'), include await nango.deleteRecordsFromPreviousExecutions('ModelName') as the last line in exec
If a sync requires metadata, set autoStart: false and define metadata as a Zod schema in the sync configuration
Document scopes in sync/action configuration (scopes: [...] in createSync or createAction)
In Zod models, mark optional properties using .optional()
For enum values in models, use z.enum([...])
Keep endpoint definitions concise and avoid redundant provider/version details in path
Use comments to explain logic and link to external API documentation
Add a comment with the external endpoint URL above each API request
Avoid mutating function arguments; prefer returning new values
ProxyConfiguration.endpoint should be a path relative to the provider base_url from providers.yaml
Import user-facing types from the models file instead of redefining them
Include .js extension for non-type imports; omit .js for type-only imports
Do not define interfaces mirroring Zod models; import the generated types from models instead
Set retries: 10 for sync proxy calls by default
Set retries: 3 for action proxy calls by default
Use await nango.log for logging; avoid console.log
Use the params property instead of appending query params to endpoint URLs
Prefer built-in nango.paginate for pagination when available
Type all requests with ProxyConfiguration
Add an API documentation link as a comment immediately above each endpoint in ProxyConfiguration
Validate script inputs and outputs with Zod
Validate and normalize date inputs using new Date; accept flexible formats and convert to provider expectations
Use nango.zodValidateInput helper for input validation
Define syncs using createSync with inline configuration
Always paginate to retrieve all records in syncs
Avoid parallelizing requests in syncs to preserve retries and rate limits
Do not wrap sync exec in try-catch; Nango manages error reporting
Batch save records early and frequently (e.g., 1...

Files:

  • integrations/hubspot/actions/get-company-by-domain.ts
  • integrations/hubspot/tests/hubspot-get-company-by-domain.test.ts
  • integrations/index.ts
integrations/**/**.ts

⚙️ CodeRabbit configuration file

integrations/**/**.ts: - Use TypeScript best practices and ensure typings are strictly defined.

  • Use comments to explain logic and link to external API documentation.
  • Place endpoint URLs as comments above API requests.
  • Avoid modifying arguments and prefer returning new values.
  • Create a types.ts file containing typed third-party API responses.
  • Proxy calls should use retries (default: 10).
  • Use await nango.log() instead of console.log for logging.
  • Use the params property in proxy calls instead of appending params onto the endpoint.
  • Use nango.paginate wherever possible for pagination.
  • Always use ProxyConfiguration for proxy request configurations.
  • Validate inputs/outputs using zod.
  • Ensure date inputs are valid and converted using new Date() to the provider's expected format.

Syncs

  • Use createSync() to define sync configuration inline.
  • The exec function must be the default export and placed at the top.
  • Always paginate requests to ensure all records are retrieved.
  • Avoid parallel requests to maintain the retry policy and prevent rate limits.
  • Mapping logic should be in a dedicated function.
  • Shared mapping logic should be stored in a mappers directory.
  • Mapper files should follow the mappers/to-{entity}.ts naming convention.
  • Avoid type casting and rely on TypeScript's type checking.
  • If the sync is incremental, use nango.lastSyncDate.

Actions

  • Use createAction() to define action configuration inline.
  • The exec function must be the default export and placed at the top.
  • Use ActionError only for specific error messages, otherwise rely on script failure.

Example:

throw new nango.ActionError<ActionErrorResponse>({
  message: 'Missing some parameter that will prevent the action from successfully running'
});

TypeScript Development Guidelines

Syncs

  • Use createSync() to define syncs with inline configuration
  • Always paginate requests to retrieve all records
  • Avoid parallel...

Files:

  • integrations/hubspot/actions/get-company-by-domain.ts
  • integrations/hubspot/tests/hubspot-get-company-by-domain.test.ts
  • integrations/index.ts
**/*.{test,spec}.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/typescript-development-guidelines-shortcuts.mdc)

Confirm test coverage

Files:

  • integrations/hubspot/tests/hubspot-get-company-by-domain.test.ts
**/index.ts

📄 CodeRabbit inference engine (.cursor/rules/nango-script-best-practices.mdc)

When adding a new integration, do not remove unrelated entries in index.ts

Files:

  • integrations/index.ts
integrations/**/index.ts

⚙️ CodeRabbit configuration file

integrations/**/index.ts: - Use createSync() and createAction() for inline configuration.

  • If syncType: 'full', then the sync should also have await nango.deleteRecordsFromPreviousExecutions as the last line in the sync with the model name as the argument.

  • If the sync requires metadata, set autoStart: false and document the metadata as a Zod schema.

  • Scopes should be explicitly documented in the scopes array.

  • Use Zod schemas for input, output, and metadata validation.

  • Define models using Zod schemas in models.ts files.

  • If syncType: 'full', then the sync should also have await nango.deleteRecordsFromPreviousExecutions("ModelName") as the last line in the sync code

  • If the sync requires metadata, then the sync should be set to autoStart: false. The metadata should be defined as a Zod schema in the sync configuration

  • Scopes should be documented in the sync/action configuration

  • For optional properties in models, use the .optional() method in Zod schemas

  • Endpoints should be concise and simple, not necessarily reflecting the exact third-party API path

  • Model names and endpoint paths should not be duplicated within an integration

  • When adding a new integration, take care to not remove unrelated entries in the index.ts file

  • For enum values in models, use Zod's .enum() method

Files:

  • integrations/index.ts
🧠 Learnings (1)
📚 Learning: 2025-09-29T10:08:50.360Z
Learnt from: CR
Repo: NangoHQ/integration-templates PR: 0
File: .cursor/rules/nango-script-best-practices.mdc:0-0
Timestamp: 2025-09-29T10:08:50.360Z
Learning: Applies to **/index.ts : When adding a new integration, do not remove unrelated entries in index.ts

Applied to files:

  • integrations/hubspot/tests/hubspot-get-company-by-domain.test.ts
  • integrations/index.ts
🪛 GitHub Actions: Lint
integrations/hubspot/actions/get-company-by-domain.ts

[error] 7-7: prettier/prettier: Delete ⏎········ (unnecessary newline). Please format the file.

🪛 GitHub Check: lint-code
integrations/hubspot/actions/get-company-by-domain.ts

[failure] 7-7:
Delete ⏎········

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: tests (ubuntu-latest, 22.x)
  • GitHub Check: tests (ubuntu-latest, 20.x)
🔇 Additional comments (10)
integrations/hubspot/mocks/get-company-by-domain/input.json (1)

1-3: Input mock is valid.

The JSON structure is correct and provides a realistic test input with the domain parameter.

integrations/hubspot/mocks/get-company-by-domain/output.json (2)

1-5: Output mock is valid.

The JSON structure is well-formed. However, verify that the output fields (particularly created_at) match the schema definition in your action implementation and the HubSpot CRM v3 search API response structure.


1-5: Note: PR checklist shows critical items unchecked.

Your PR checklist indicates that "I added tests" and other best practices are unchecked. Ensure that:

  • Unit tests exist and pass for this action
  • External API calls include proper retries
  • All other checklist items are addressed before merging
integrations/hubspot/mocks/nango/post/proxy/crm/v3/objects/companies/search/get-company-by-domain/21ca0bdc7ba4b2bed957f428e1b3ceb43e07bced.json (1)

1-50: Mock payload matches HubSpot search usage

The mock request/response shape (filters on domain, properties: ['name','domain','createdate'], and top-level createdAt) aligns with the new action’s expectations and should work well for tests.

integrations/index.ts (1)

329-329: HubSpot action import wiring looks correct

The new get-company-by-domain action is registered consistently with other HubSpot actions, and no unrelated entries were touched.

integrations/package.json (1)

15-21: Clarify nango downgrade to 0.69.14

The root package.json pins nango to ^0.69.18, but integrations/package.json pins it to 0.69.14. Confirm this downgrade is intentional and doesn't drop needed features or bugfixes for your workflow.

integrations/.nango/schema.ts (1)

2-2: Header version bump is fine

The generator version update to v0.69.14 is consistent with an auto-regenerated schema and has no functional impact. Just keep it in sync with the Nango version in package.json.

integrations/.nango/schema.json (3)

26793-26830: Clarify schema design for nullable required fields.

The output schema marks name and created_at as both required and nullable (type: ["string", "null"]). This is technically valid but semantically ambiguous—does the action guarantee these fields will be present (possibly as null), or can they be omitted? Verify this design matches the handler implementation and API contract.


62677-62677: Explain the Nango version downgrade.

The schema was generated with Nango v0.69.14, representing a downgrade from v0.69.17. Clarify the reason: Is there a regression in newer versions, or a compatibility issue with this action? This should be documented in the PR description.


26793-26830: Verify PR checklist completeness.

The PR description shows all checklist items unchecked (tests, retries, pagination, metadata handling). Since this file is auto-generated, the actual implementation details—handler logic, error handling, retry configuration, and test coverage—aren't visible here. Please ensure the implementation files (integrations/hubspot/actions/get-company-by-domain.ts and corresponding tests) meet the integration guidelines before merging.

Comment on lines +5 to +67
// Input schema
const GetCompanyByDomainInput = z.object({
domain: z.string()
.describe('Company domain to search for. Example: "nango.dev"')
});

// Output schema
const GetCompanyByDomainOutput = z.object({
name: z.union([z.string(), z.null()]),
domain: z.string(),
created_at: z.union([z.string(), z.null()])
});

const action = createAction({
description: 'Fetch a company by domain from HubSpot',
version: '1.0.0',

endpoint: {
method: 'POST',
path: '/company/search',
group: 'Companies'
},

input: GetCompanyByDomainInput,
output: GetCompanyByDomainOutput,
scopes: ['crm.objects.companies.read'],

exec: async (nango, input): Promise<z.infer<typeof GetCompanyByDomainOutput>> => {
const config: ProxyConfiguration = {
// https://developers.hubspot.com/docs/api/crm/search
endpoint: 'crm/v3/objects/companies/search',
data: {
filterGroups: [
{
filters: [
{
propertyName: 'domain',
operator: 'EQ',
value: input.domain
}
]
}
],
properties: ['name', 'domain', 'createdate']
},
retries: 3
};

const response = await nango.post(config);

// Extract first result from search
const company = response.data.results?.[0];

if (!company) {
throw new Error(`No company found with domain: ${input.domain}`);
}

return {
name: company.properties?.name ?? null,
domain: company.properties?.domain,
created_at: company.createdAt ?? null
};
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# First, locate the file and check its current state
find . -name "get-company-by-domain.ts" -type f 2>/dev/null | head -20

Repository: NangoHQ/integration-templates

Length of output: 128


🏁 Script executed:

#!/bin/bash
# List HubSpot integration structure
ls -la integrations/hubspot/actions/ 2>/dev/null | head -20

Repository: NangoHQ/integration-templates

Length of output: 1325


🏁 Script executed:

#!/bin/bash
# Check if file exists and show its content
if [ -f "integrations/hubspot/actions/get-company-by-domain.ts" ]; then
  wc -l "integrations/hubspot/actions/get-company-by-domain.ts"
  echo "---FILE CONTENT---"
  cat -n "integrations/hubspot/actions/get-company-by-domain.ts"
else
  echo "File not found"
  find . -path "*/hubspot/actions*" -type f 2>/dev/null | head -10
fi

Repository: NangoHQ/integration-templates

Length of output: 2740


🏁 Script executed:

#!/bin/bash
# Check coding guidelines application for .ts files in integrations
rg "Document all code|JSDoc" . --type ts -B 2 -A 2 | head -30

Repository: NangoHQ/integration-templates

Length of output: 55


🏁 Script executed:

#!/bin/bash
# Check for existing JSDoc patterns in other HubSpot actions
find integrations/hubspot/actions -name "*.ts" -type f 2>/dev/null | head -3 | xargs -I {} sh -c 'echo "=== {} ===" && head -30 {}'

Repository: NangoHQ/integration-templates

Length of output: 3284


🏁 Script executed:

#!/bin/bash
# Check for nango.ActionError usage patterns in existing actions
rg "nango\.ActionError|throw new Error" integrations/hubspot/ -A 2 | head -40

Repository: NangoHQ/integration-templates

Length of output: 2035


Replace generic Error with nango.ActionError and fix domain output typing

Two issues need fixing:

  1. Use nango.ActionError for the "no company found" case
    Line 59 uses a generic Error, but all other HubSpot actions throw nango.ActionError for actionable errors. Change to:

    -        if (!company) {
    -            throw new Error(`No company found with domain: ${input.domain}`);
    -        }
    +        if (!company) {
    +            throw new nango.ActionError({
    +                message: `No company found with domain: ${input.domain}`
    +            });
    +        }
  2. Guarantee the domain field in the return object
    Line 64 returns company.properties?.domain, which could be undefined. The Zod schema (line 14) requires domain: z.string(). Fallback to the input domain:

    -            domain: company.properties?.domain,
    +            domain: company.properties?.domain ?? input.domain,
🧰 Tools
🪛 GitHub Actions: Lint

[error] 7-7: prettier/prettier: Delete ⏎········ (unnecessary newline). Please format the file.

🪛 GitHub Check: lint-code

[failure] 7-7:
Delete ⏎········

🤖 Prompt for AI Agents
In integrations/hubspot/actions/get-company-by-domain.ts around lines 5-67,
replace the generic throw new Error(...) when no company is found with throw new
nango.ActionError(...) so the action uses the platform-specific error type, and
ensure the returned domain is always a string by returning
company.properties?.domain ?? input.domain (or otherwise coercing to
input.domain) so it matches the Zod schema's required string type.

const GetCompanyByDomainOutput = z.object({
name: z.union([z.string(), z.null()]),
domain: z.string(),
created_at: z.union([z.string(), z.null()])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

z.string().nullable() is more concise

const company = response.data.results?.[0];

if (!company) {
throw new Error(`No company found with domain: ${input.domain}`);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should it throw or return an empty result?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants