From hubspot-pack
Debugs complex HubSpot API issues via layer-by-layer tests (DNS/TCP/TLS/HTTP/auth/rate-limits), correlation ID tracking, and evidence collection for support escalation.
How this skill is triggered — by the user, by Claude, or both
Slash command
/hubspot-pack:hubspot-advanced-troubleshootingThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Deep debugging techniques for complex HubSpot API issues: systematic layer testing, timing analysis, correlation ID tracking, and support escalation.
Deep debugging techniques for complex HubSpot API issues: systematic layer testing, timing analysis, correlation ID tracking, and support escalation.
curl and jq availableTest each layer independently to isolate the failure:
#!/bin/bash
# hubspot-layer-test.sh
echo "=== HubSpot Layer-by-Layer Diagnostic ==="
# Layer 1: DNS Resolution
echo "1. DNS Resolution"
dig api.hubapi.com +short || echo "FAIL: DNS resolution"
# Layer 2: TCP Connectivity
echo "2. TCP Connectivity"
timeout 5 bash -c 'echo > /dev/tcp/api.hubapi.com/443' 2>/dev/null \
&& echo "OK" || echo "FAIL: Cannot reach port 443"
# Layer 3: TLS Handshake
echo "3. TLS Handshake"
echo | openssl s_client -connect api.hubapi.com:443 2>/dev/null | grep "Verify return code"
# Layer 4: HTTP Response (unauthenticated)
echo "4. HTTP Response (no auth)"
curl -so /dev/null -w "HTTP %{http_code} in %{time_total}s\n" \
https://api.hubapi.com/crm/v3/objects/contacts?limit=1
# Layer 5: Authenticated Request
echo "5. Authenticated Request"
RESPONSE=$(curl -s -w "\n%{http_code}" \
https://api.hubapi.com/crm/v3/objects/contacts?limit=1 \
-H "Authorization: Bearer $HUBSPOT_ACCESS_TOKEN")
HTTP_CODE=$(echo "$RESPONSE" | tail -1)
BODY=$(echo "$RESPONSE" | head -n -1)
echo "HTTP $HTTP_CODE"
if [ "$HTTP_CODE" = "200" ]; then
echo "OK: API accessible"
echo "Records: $(echo $BODY | jq '.results | length')"
else
echo "FAIL: $(echo $BODY | jq -r '.category // .message')"
echo "Correlation ID: $(echo $BODY | jq -r '.correlationId // "none"')"
fi
# Layer 6: Rate Limit State
echo "6. Rate Limit State"
curl -sI https://api.hubapi.com/crm/v3/objects/contacts?limit=1 \
-H "Authorization: Bearer $HUBSPOT_ACCESS_TOKEN" \
| grep -i "ratelimit" | sed 's/^/ /'
Every HubSpot error response includes a correlationId. Track these for support:
import * as hubspot from '@hubspot/api-client';
// Collect correlation IDs from errors
const errorLog: Array<{
timestamp: string;
correlationId: string;
statusCode: number;
category: string;
message: string;
endpoint: string;
}> = [];
async function debuggedApiCall<T>(
endpoint: string,
operation: () => Promise<T>
): Promise<T> {
try {
return await operation();
} catch (error: any) {
const body = error?.body || {};
const entry = {
timestamp: new Date().toISOString(),
correlationId: body.correlationId || 'unknown',
statusCode: error?.code || error?.statusCode || 500,
category: body.category || 'UNKNOWN',
message: body.message || error.message,
endpoint,
};
errorLog.push(entry);
console.error('HubSpot error:', entry);
throw error;
}
}
// Dump error log for support ticket
function getErrorReport(): string {
return errorLog.map(e =>
`[${e.timestamp}] ${e.statusCode} ${e.category} | ${e.correlationId} | ${e.endpoint}: ${e.message}`
).join('\n');
}
async function timingAnalysis() {
const operations = [
{
name: 'GET contacts (single)',
fn: () => client.crm.contacts.basicApi.getPage(1, undefined, ['email']),
},
{
name: 'SEARCH contacts',
fn: () => client.crm.contacts.searchApi.doSearch({
filterGroups: [{
filters: [{ propertyName: 'lifecyclestage', operator: 'EQ', value: 'lead' }],
}],
properties: ['email'], limit: 1, after: 0, sorts: [],
}),
},
{
name: 'GET pipelines',
fn: () => client.crm.pipelines.pipelinesApi.getAll('deals'),
},
{
name: 'GET properties',
fn: () => client.crm.properties.coreApi.getAll('contacts'),
},
];
console.log('=== HubSpot Timing Analysis ===');
for (const op of operations) {
const times: number[] = [];
for (let i = 0; i < 5; i++) {
const start = performance.now();
try {
await op.fn();
times.push(performance.now() - start);
} catch {
times.push(-1); // mark failures
}
}
const successful = times.filter(t => t >= 0);
if (successful.length > 0) {
console.log(`${op.name}:
Min: ${Math.min(...successful).toFixed(0)}ms
Max: ${Math.max(...successful).toFixed(0)}ms
Avg: ${(successful.reduce((a, b) => a + b, 0) / successful.length).toFixed(0)}ms
Failures: ${times.length - successful.length}/5`);
} else {
console.log(`${op.name}: ALL FAILED`);
}
}
}
// Reproduce common intermittent issues
// Test 1: Rapid sequential calls (rate limit sensitivity)
async function testRateLimit(requestCount = 20) {
console.log(`Sending ${requestCount} rapid requests...`);
let success = 0, rateLimited = 0, errors = 0;
for (let i = 0; i < requestCount; i++) {
try {
await client.crm.contacts.basicApi.getPage(1, undefined, ['email']);
success++;
} catch (error: any) {
if (error?.code === 429) rateLimited++;
else errors++;
}
}
console.log(`Results: ${success} ok, ${rateLimited} rate limited, ${errors} errors`);
}
// Test 2: Concurrent requests (connection pool issues)
async function testConcurrency(concurrent = 10) {
console.log(`Sending ${concurrent} concurrent requests...`);
const results = await Promise.allSettled(
Array.from({ length: concurrent }, () =>
client.crm.contacts.basicApi.getPage(1, undefined, ['email'])
)
);
const fulfilled = results.filter(r => r.status === 'fulfilled').length;
const rejected = results.filter(r => r.status === 'rejected').length;
console.log(`Results: ${fulfilled} ok, ${rejected} failed`);
const failures = results.filter(r => r.status === 'rejected') as PromiseRejectedResult[];
for (const f of failures) {
console.log(` Error: ${f.reason?.code} ${f.reason?.body?.category}`);
}
}
## HubSpot Support Escalation
**Severity:** P[1-4]
**Portal ID:** [your portal ID]
**Correlation IDs:** [list from error log]
### Issue Summary
[1-2 sentence description]
### Steps to Reproduce
1. Make API call: POST /crm/v3/objects/contacts/search
2. With body: { "filterGroups": [...], "properties": ["email"], "limit": 10 }
3. Observe: 500 Internal Server Error
### Error Response
```json
{
"status": "error",
"message": "[exact error message]",
"correlationId": "[exact ID]",
"category": "[exact category]"
}
## Output
- Layer-by-layer diagnostic isolating the failure point
- Correlation ID collection for support tickets
- Timing analysis identifying latency patterns
- Reproduction scripts for rate limit and concurrency issues
- Support escalation template with all required evidence
## Error Handling
| Scenario | Diagnostic | Next Step |
|----------|-----------|-----------|
| DNS fails | Check resolver config | Try `8.8.8.8` resolver |
| TLS fails | Certificate issue | Check system CA bundle |
| 401 after working | Token rotated | Regenerate in Settings |
| Intermittent 500 | HubSpot server issue | Collect correlation IDs, file ticket |
| Latency spikes | Network or HubSpot load | Run timing analysis over time |
## Resources
- [HubSpot Support Portal](https://help.hubspot.com/)
- [HubSpot Developer Community](https://community.hubspot.com/t5/APIs-Integrations/bd-p/integration)
- [Error Handling Guide](https://developers.hubspot.com/docs/api-reference/error-handling)
## Next Steps
For load testing, see `hubspot-load-scale`.
npx claudepluginhub ia23a-lachnita/claude-code-plugins-plus-fix-skills --plugin hubspot-pack4plugins reuse this skill
First indexed Jul 10, 2026
Survive HubSpot API rate limits at production scale. Covers daily 500K portal quota, per-10s burst limits, batch API efficiency (100x), token bucket pattern, queue-based worker architecture, and Retry-After header parsing. Use when a sync job burns the daily quota before 8am, when a parallelized batch job retry-storms on 429s, when single-record reads waste 99% of available throughput, or when instrumenting a rate-limit dashboard for an Ops Hub Enterprise portal. Trigger with "hubspot rate limit", "hubspot quota", "hubspot 429", "hubspot batch API", "hubspot token bucket", "hubspot throttle", "hubspot daily limit exhausted", "hubspot Ops Hub rate limit".
Provides patterns for HubSpot CRM integration including OAuth 2.0 authentication, private app tokens, CRM objects, associations, batch operations, webhooks, and custom objects using Node.js and Python SDKs.
Guides collaborative design exploration before implementation: explores context, asks clarifying questions, proposes approaches, and writes a design doc for user approval.