ERR_HUBSPOT_DEAL_STAGE on HubSpot: HubSpot deal stage update rejected. Root cause: HubSpot deal stage updates fail when the stageId value sent via the API does not match a valid pipeline stage in the target HubSpot portal. Stage IDs are pipeline-specific and account-specific — a stage ID from a sandbox account, a different pipeline, or a different HubSpot portal will always be rejected. Additionally, HubSpot's CRM API v3 uses string-based stage IDs (e.g., "appointmentscheduled") for default pipelines but UUID-based IDs for custom pipelines, and mixing these formats causes validation errors. Step 1: Fetch valid stage IDs for the target pipeline. Stage IDs are not portable between accounts or pipelines. Call GET https://api.hubapi.com/crm/v3/pipelines/deals with your access token to list all deal pipelines and their stages. Each stage has an "id" field — use this exact value when updating a deal's dealstage property. For the default HubSpot sales pipeline, stage IDs are human-readable strings like "appointmentscheduled" and "qualifiedtobuy". For custom pipelines, they are UUIDs like "a1b2c3d4-e5f6-7890-abcd-ef1234567890". Step 2: Ensure the stage belongs to the deal's current pipeline. A deal can only be moved to a stage that belongs to its current pipeline. If you want to move a deal to a stage in a different pipeline, you must update both the pipeline property and the dealstage property in the same API call: PATCH /crm/v3/objects/deals/{dealId} with body {"properties": {"pipeline": "NEW_PIPELINE_ID", "dealstage": "NEW_STAGE_ID"}}. Updating only the dealstage without updating the pipeline when the stage belongs to a different pipeline causes a validation error. Step 3: Check for required property validation on stage transitions. HubSpot allows admins to configure required properties on deal stage transitions (CRM → Deals → Pipeline settings → Edit pipeline → Required properties). If a stage transition requires a property (e.g., "Close Date" must be set before moving to "Contract Sent"), the API will reject the stage update with a validation error listing the missing required properties. Check the pipeline settings in HubSpot and ensure your API call includes all required properties for the target stage. Step 4: Handle HubSpot API rate limits correctly. HubSpot enforces rate limits based on your subscription: Free/Starter accounts get 100 requests per 10 seconds; Professional/Enterprise get 150 requests per 10 seconds. For private apps (the recommended authentication method), the limit is 100 requests per 10 seconds regardless of tier. When you exceed the limit, HubSpot returns 429 with a "X-HubSpot-RateLimit-Remaining" header showing 0 and a "Retry-After" header. Implement retry logic that waits for the Retry-After duration before retrying. For bulk updates, use HubSpot's batch update endpoint: POST /crm/v3/objects/deals/batch/update. Step 5: Migrate from legacy API keys to Private Apps. HubSpot deprecated API keys (hapikey parameter) in November 2022. If your integration is still using ?hapikey=YOUR_KEY in API calls, it may stop working at any time. Migrate to a Private App: in HubSpot, go to Settings → Integrations → Private Apps, create a new app with the required scopes (crm.objects.deals.write for deal updates), and use the generated access token as a Bearer token in the Authorization header. Private App tokens do not expire but can be regenerated if compromised. Step 6: Use HubSpot's CRM timeline to audit failed updates. After a failed deal stage update, check the deal's activity timeline in HubSpot (CRM → Deals → open the deal → Activity tab). HubSpot logs all property changes including failed API attempts. If the stage update was rejected due to a required property validation, the timeline shows which property was missing. This is faster than debugging API logs and gives you the exact field name and validation rule that blocked the update.