Errors
Every error the plugsync API returns to your code, in one place: what the status and the code mean, which field of the body carries the code, and what to do about it. It covers the routes you call with a session, an organization API key or a connector API key. The dashboard calls the same routes, so an error it shows is one of these.
Reading an error
An error response is JSON with a top-level detail key. What
detail holds depends on the route, and there are four shapes:
detail is | Example | Where the code is |
|---|---|---|
| A string | {"detail": "Invalid or revoked API key"} | The string itself. Match on the exact text only where this page lists it; elsewhere treat it as a message for a person. |
An object with error | {"detail": {"error": "owner_required"}} | detail.error. Most structured errors use this shape, often with a message for a person and extra fields named in the tables below. |
An object with code | {"detail": {"code": "publish_review_required", "message": "..."}} | detail.code. Used by publish and its review gate, and by the AI assistant. |
| A list | {"detail": [{"type": "missing", "loc": ["body", "event"], "msg": "Field required", "input": {...}}]} | Request validation (422): one entry per invalid field, with its location in loc. |
A few routes answer an object with other keys, and are called out where they
appear: the HubSpot record read-back
uses detail.status, the publish 409 for a stale base version carries
version numbers only, and the
legacy compat ingress keeps the
{"result": ..., "message": ...} shape of the system it replaces.
Request id. Every response, success or error, carries an X-Request-ID
header. A well-formed X-Request-ID sent with the request is echoed back;
otherwise one is generated. Quote it when you contact support. An unexpected server error
answers 500 with {"detail": "internal_error", "request_id": "..."}: the
request_id is the same value as the header.
Retry-After. Where the wait before a retry is known, the response says
how long in the Retry-After header, in seconds: on the per-second rate
limit, on the attempt limits of signup, email verification codes, resending
the verification email, Google sign-in, two-factor codes, password
confirmations and password reset requests, on
429 connector_flow_breaker_open and on 503 credential_refresh_busy.
Status codes at a glance
| Status | Meaning | What to do |
|---|---|---|
400 | The request is well formed but cannot apply to the current state (a source of the wrong type, an expired link, an invalid token). | Read detail and fix the request. Retrying unchanged gives the same answer. |
401 | No valid credential: missing or revoked key, expired or invalid session token, wrong password or two-factor code. | See Authentication and access. |
402 | The organization’s plan does not include this, or a plan limit is reached (connectors, seats, portals, event sources, custom objects, plugins, SLA monitoring, AI assistant sessions). detail carries error, tier, a message and an upgrade_url, plus limit and usage where they apply. The monthly event quota answers 429 instead. | Upgrade the plan from upgrade_url, or free a slot (delete an unused connector, source or seat). Each code and its way out: Plan limits. |
403 | Authenticated, but not allowed: wrong role, a key where a person is required, another organization. | See Authentication and access. |
404 | The resource does not exist, or belongs to another organization. The two answer the same on purpose. | Check the id and the organization the credential belongs to. |
405 | The method is not supported on that path (for example PATCH on a credential, PUT on a source). | Use the method the detail names. |
409 | The request conflicts with the current state: a concurrent edit, a confirmation needed, a name already taken. | The tables below name each code. Most 409s are resolved by re-reading the resource, or by resending with an explicit confirmation flag. |
410 | Gone for good: an expired or revoked link, invitation or export, a disabled webhook source, or a removed endpoint. | Get a new link, invitation or export. A removed endpoint names its replacement in detail. |
422 | The request body or the config fails validation. | Read detail: a list names the invalid fields, an object names the rule. |
423 | The connector or the organization is stopped, so the request is refused rather than queued. | See Suspended or closing organization and Event API ingest. |
429 | Too many requests, the monthly event quota, or a paused flow. | See the three causes of 429. Wait for Retry-After when present. |
500 | Unexpected server error. | Retry later; if it persists, contact support with the request_id. |
502 | An upstream system (HubSpot, a plugin, an external API) failed or answered something unexpected. | Usually transient: retry with backoff. Some 502s leave the outcome unknown and say so: read before retrying. |
503 | A platform dependency is briefly unavailable. Nothing was accepted. | Retry with backoff, after Retry-After when present. |
Authentication and access
How credentials, roles and the active organization work is in Authentication, API keys and roles. These are the errors they produce.
| Status | Code | Read | Meaning | What to do |
|---|---|---|---|---|
401 | Not authenticated | detail | A route that needs Authorization: Bearer called without the Authorization header, or with a scheme other than Bearer. The response carries WWW-Authenticate: Bearer. | Send Authorization: Bearer <token or API key>. |
401 | Missing x-api-key header | detail | An event-plane call (/api/v1/events, bulk import) without the x-api-key header. | Send the connector key in x-api-key, not as Authorization: Bearer. |
401 | Invalid or revoked API key | detail | The key is unknown, revoked or, for an organization key, past its expires_at. On the event plane, also an organization key sent in x-api-key. | Create a new key; use a connector key on the event plane. |
401 | Invalid token, Invalid token claims, Token missing required claims | detail | The session token is expired or malformed, or a connector key was sent as Bearer on the config plane. | Refresh the session or log in again. |
401 | User not found | detail | The token, or the refresh, names a user that no longer exists or was deactivated. | Log in again; if the account was deactivated, contact support. |
401 | No refresh token, Invalid refresh token, Token reuse detected | detail | The session refresh failed. A reused refresh token ends every session of the user. | Log in again. |
401 | Invalid credentials | detail | Wrong email or password at login. | Check them; reset the password if needed. |
401 | account_deactivated | detail.error | The user account is deactivated. | Contact support. |
403 | owner_required | detail.error | The route needs an owner and the caller is a member, or an organization key on a route that needs a signed-in owner. | Ask an owner. The list is in Owner-only actions and Owner or organization key. |
403 | user_auth_required | detail.error | A billing action called with an organization key: opening a checkout, previewing a plan change, opening the billing portal, editing the billing details, reading the order confirmations or the agreement. Reading the plan (GET /api/v1/billing/me) accepts keys. Also a route that acts on the user account (PATCH /api/me, POST /api/me/active-organization, /password, /email, /email/confirm, /api/me/mfa/...) called with a key; GET /api/me accepts keys. | Call it from a signed-in session. See Actions that need a signed-in user. |
403 | user_session_required | detail.error | Accepting the legal documents, or attaching a HubSpot install to an organization, called with an organization key. | Call it from a signed-in session. |
403 | api_key_cannot_create_org, api_key_cannot_create_test_connector | detail.error | An organization key tried to create an organization, or a test-mode connector. | Use a session. |
403 | wrong_active_org | detail.error | A route under /api/orgs/{org_id}/... was called for an organization that is not the session’s active one. | Switch the active organization first. |
403 | not_a_member | detail.error | Switching the active organization (POST /api/me/active-organization) to one the user does not belong to. | Pick an organization from GET /api/me. |
403 | no_active_organization | detail.error | Login or refresh for a user who belongs to no organization. | Accept an invitation, or sign up to create one. |
403 | User is not a member of the requested organization | detail | The session names an organization the user no longer belongs to. | Log in again. |
403 | CSRF validation failed | detail | A session refresh or logout without the X-CSRF-Token header matching the CSRF cookie. | Send the header with the cookie value. |
403 | email_not_verified | detail.error | Login before the email address is verified. detail.resend_url is the route that sends a new verification email. | Verify the email, or call resend_url. |
Sessions and account
Signup, email verification, password, profile and two-factor settings.
| Status | Code | Read | Meaning | What to do |
|---|---|---|---|---|
409 | email_already_registered | detail.error | Signup (or a HubSpot install signup) with an email that already has an account. | Log in instead. |
400 | token_invalid, token_expired, token_consumed | detail.error | A verification or password-reset link that is wrong, past its expiry or already used. | Request a new link. |
404 | user_not_found | detail.error | The link points at a user that no longer exists. | Sign up again. |
400 | code_invalid, code_expired | detail.error | A wrong or expired email verification code. | Re-enter it, or request a new code. |
429 | code_locked | detail.error | Too many wrong guesses on the current code. | Request a new code. |
429 | code_attempts_exhausted | detail.error | The signup used up its wrong guesses across every code sent: the code path is closed and no new code reopens it. | Verify with the link in the verification email. |
403 | verification_tab_required | detail.error | The code was submitted from a different browser than the signup, or no code is pending for that email. | Enter it in the tab where you signed up, or use the link in the verification email. |
401 | invalid_mfa_token, invalid_mfa_code | detail.error | The two-factor step of a login failed: the pending login expired, or the code is wrong. | Log in again, or re-enter the code. |
401 | google_mfa_expired | detail.error | The two-factor step after a Google sign-in took too long. | Sign in with Google again. |
401 | invalid_code, wrong_password | detail.error | Enabling or disabling two-factor, changing the password or the email, or closing the organization, with a wrong code or password. | Re-enter it. |
409 | mfa_already_enabled, enrollment_already_in_progress | detail.error | Two-factor is already on, or an enrollment is already pending. | Finish or cancel the pending enrollment. |
400 | no_pending_enrollment, mfa_not_enabled | detail.error | Confirming an enrollment that was never started, or disabling two-factor that is off. | Start the enrollment first. |
400 | password_too_short | detail.error | The new password is too short. | Choose a longer one. |
400 | same_email, no_pending_change, token_consumed_or_invalid | detail.error | An email change to the current address, a confirmation with no change pending, or a used confirmation link. | Start the change again. |
409 | email_taken | detail.error | The new email already belongs to another account. | Use another address. |
403 | token_subject_mismatch | detail.error | An email-change link opened by a different user than the one who asked for it. | Open it signed in as that user. |
409 | google_account_mismatch | detail.error | The Google account is linked to a different plugsync user. | Sign in with the matching Google account. |
429 | Too many signup requests | detail | Too many signups, including Google sign-ins that create an account, from the same address. | Wait for Retry-After. |
429 | Too many verification attempts | detail | Too many verification codes submitted from the same address. | Wait for Retry-After. |
429 | Too many verification requests | detail | Too many requests to resend the verification email, for the same email or from the same address. | Wait for Retry-After. |
429 | Too many sign-in attempts | detail | Too many Google sign-ins from the same address. | Wait for Retry-After. |
429 | Too many MFA verification attempts | detail | Too many two-factor codes for the same user, at login or in the two-factor settings. | Wait for Retry-After. |
429 | Too many password change attempts | detail | Too many password confirmations for the same user: changing the password, or closing the organization. | Wait for Retry-After. |
429 | Too many password reset requests | detail | Too many password reset requests for the same email. | Wait for Retry-After. |
Google sign-in
Continue with Google is a browser flow: it does not answer with a JSON
error but sends the browser back to the page it started from (/login,
/signup or the HubSpot install page) with the code in the
google_error query parameter, and the page shows the message. Two codes
land on a fixed page: google_link_requires_password on /login when
the flow started from /signup, and google_complete_signup always on
/signup. How each
case arises is in
Getting started: continue with Google.
| Code | Page message | What to do |
|---|---|---|
google_access_denied | ”Google sign-in was cancelled.” | Start again. |
google_account_not_found | ”No plugsync account uses this Google address yet. Sign up to create one.” | Sign up instead of logging in. |
google_email_not_verified | ”Google has not verified this email address, so it cannot be used to sign in.” | Verify the address with Google, or sign up with the form. |
email_not_verified | ”Verify your email address first: open the link in the email we sent you, then continue with Google.” | Open the verification link. |
google_link_requires_password | ”An account with this email already exists, and Google cannot confirm it controls this email domain. Sign in with your password.” | Sign in with the password. |
google_complete_signup | ”This email has an account that was never verified. Accept the terms below and continue with Google to take it over.” (on /signup) | Accept the terms and continue with Google. |
google_account_mismatch | ”This plugsync account is linked to a different Google account. Continue with that one, or sign in with your password.” | Use the linked Google account, or the password. |
account_deactivated | ”This account is deactivated.” | Contact support@plugsync.com. |
email_already_registered | ”Google sign-in failed. Please try again.” | An account was created with this email meanwhile: sign in. |
google_state_expired | ”The Google sign-in took too long. Please try again.” | Start again: the round trip has 10 minutes. |
google_unavailable | ”Google cannot be reached right now. Please try again in a few minutes.” | Retry later. |
legal_document_version_outdated | ”Our legal documents changed while you were signing in. Review them and try again.” | Accept the current version and start again. |
google_sign_in_failed, rate_limited and any other code | ”Google sign-in failed. Please try again.” | Start again; after too many attempts wait a few minutes. |
The two-factor step that follows a Google sign-in on an account with
two-factor on (POST /api/v1/auth/google/mfa) is an API call and answers
JSON: 401 google_mfa_expired, 401 invalid_mfa_code and
409 google_account_mismatch, in the table above.
Team and invitations
The team model is in Managing the team.
| Status | Code | Read | Meaning | What to do |
|---|---|---|---|---|
409 | already_member | detail.error | The invited email already belongs to a member. | Nothing to do. |
409 | invitation_pending | detail.error | An invitation to that email is already open. | Revoke it and invite again, or let it be accepted. |
402 | seat_limit_reached | detail.error | Inviting one more person would exceed the plan’s seats (members plus open invitations); accepting an invitation checks again. | Upgrade, revoke an open invitation or remove a member. See Team seats. |
409 | last_owner | detail.error | The change would leave the organization without an owner. | Promote another owner first. |
400 | invalid_role | detail.error | A role other than owner or member. | Use one of the two. |
404 | membership_not_found, target_not_member, invitation_not_found | detail.error | The user is not a member, or the invitation does not exist. | Check the id. |
400 | token_invalid, signup_required | detail.error | Accepting with a wrong token, or with no account for the invited email. | Sign up with the invited email, then accept. |
401 | login_required | detail.error | Accepting an invitation without being signed in. | Sign in, then accept. |
403 | email_mismatch | detail.error | The signed-in user is not the invited email. | Sign in as the invited address. |
409 | already_accepted | detail.error | The invitation was already accepted. | Nothing to do. |
410 | token_expired, invitation_revoked, invitation_consumed | detail.error | The invitation expired, was revoked, or was used. | Ask an owner for a new invitation. |
Draft and publish
How drafts and publishing work is in
the draft -> publish workflow. Publish
answers 409 in two different shapes: tell them apart by the presence of
detail.code.
| Status | Code | Read | Meaning | What to do |
|---|---|---|---|---|
409 | none | detail.current_active_version, detail.your_base_version | Someone else published since your draft was started: the draft’s base version is no longer the active one. | Reset the draft (POST /api/connectors/{id}/draft/reset) or keep editing and review again. See Concurrency. |
409 | publish_review_required | detail.code | The organization’s policy (detail.policy, dry_run_required) asks for the HubSpot properties and pipelines this publish would create to be reviewed first. detail.artifacts lists them, detail.draft_version is the draft revision to confirm. | Read GET /api/connectors/{id}/publish-review, confirm with POST /api/connectors/{id}/publish-review/confirm and {"draft_version": N}, then publish again. |
409 | stale_publish_review | detail.code | The confirmation names a draft revision that is no longer current (your_draft_version vs current_draft_version): the draft changed after the review. | Read the review again and confirm the current revision. |
422 | none | detail.message, detail.errors, detail.provisioned | Creating the HubSpot properties or pipelines failed. No version was created; what the run created on the portal stays there. | Fix the cause named in errors and publish again: the retry resumes from the failure. See Failure behavior. |
422 | config_too_large | detail.error | The compiled config is over the size limit (size_bytes, limit_bytes). | Shrink the config. See Config size limit. |
422 | credential_not_found, credential_ambiguous, credential_type_mismatch | detail.error | A source names a credential (credential_name) that does not exist, exists twice, or is of a type the source cannot use. available lists the names that would work; path is set when the reference is not the source’s own credential_name, and source names the source. A publish is refused for a source it creates, and for an existing source that stays enabled and in use; otherwise the same code comes back in the publish warnings. | Fix the name, or create the credential. See When a source’s credential does not resolve. |
422 | varies | detail.error, detail.field | The config fails a rule tied to one field (for example a batch action in a config that declares version: "3.0"). | Fix the field named in field. |
422 | none | detail (string) | Any other config validation failure. The string names the rule. | Fix the config. |
422 | none | detail (string) | A publish lists the same name in both new_sources and delete_sources. The string names them: names cannot appear in both new_sources and delete_sources: [...]. | Keep each name in one list. See new_sources and delete_sources. |
402 | event_source_limit_reached | detail.error | The publish would bring the organization over its plan’s event sources. | Upgrade, or remove a source. See Event sources. |
409 | draft_version_conflict | detail.error | A draft write sent expected_version and the draft has moved on (current_version). | Read the draft again and reapply the change. |
422 | sources_key_removal_not_supported | detail.error | A PUT /draft without the sources key, or a PATCH /draft with "sources": null. | Send "sources": [] to declare no sources. See sources. |
422 | none | detail (string) | A draft write whose body misses its required top-level fields. The string names the expected shape. | Send the config or patch object as the body. |
402 | custom_objects_not_allowed, custom_object_type_limit_reached | detail.error | The draft declares custom objects the plan does not include, or more custom object types than it allows. | Upgrade, or remove them. See Custom objects. |
410 | none | detail (string) | A removed config endpoint (/configs, /entities, /event-flows). | Use the draft endpoints the message names. |
Sources and credentials
Sources are managed under /api/connectors/{connector_id}/sources: see
The API of the event
sources reference.
| Status | Code | Read | Meaning | What to do |
|---|---|---|---|---|
422 | secret_not_declarable | detail.error | A secret in a source definition. | Leave it out: a secret is generated, rotated and read on the source. See Secrets. |
422 | mixed_row_and_definition_fields | detail.error | One PATCH mixes enabled (or a rename) with config or type. | Send one call per half. |
422 | source_type_immutable | detail.error | A PATCH or publish that changes a source’s type. | Create a new source instead. |
404 | source_not_published | detail.error | An action that needs a live source (rotate secret, test webhook, full extract, rename) on a source that only exists in the draft. | Publish first. |
409 | source_referenced_by_draft_flows | detail.error | Deleting a source that a flow of the draft still reads or writes (references). | Remove or repoint those flows first. |
409 | event_source_delete_confirmation_required | detail.error | Deleting a source while the organization is over its plan’s event sources: it could not create a replacement afterwards. | PATCH the source in place, or resend the DELETE with confirm=true. |
402 | event_source_limit_reached | detail.error | Creating a source over the plan’s limit. | Upgrade, or remove a source. See Event sources. |
422 | credential_not_found, credential_ambiguous, credential_type_mismatch | detail.error | As in Draft and publish. | Fix the credential_name. |
404, 400 | source_not_found, source_not_pollable, source_disabled | detail.error | POST /api/connectors/{id}/sync?source= names a source that cannot be polled now. pollable_sources lists the ones that can. | See Polling a source on demand. |
405 | none | detail | PUT on a source. | Use PATCH. |
409 | credential_name_taken | detail.error | Creating or renaming a credential to a name already used in the organization (name, and existing_id when known). | Pick another name, or update that credential. |
409 | credential_referenced_by_sources | detail.error | Deleting or renaming a credential that sources still name (sources). | Repoint the sources first. |
405 | none | detail | PATCH on a credential. | Use PUT. |
409 | disconnect_confirmation_required | detail.error | Disconnecting a HubSpot credential that connectors use. detail lists the connectors and the identity mappings that would be affected. | Resend with confirm=true. See Disconnecting a portal instead. |
502 | Identity mapping purge failed; disconnect aborted. | detail | Disconnecting a HubSpot credential, the identity mappings of its connectors could not be removed. Nothing was disconnected. | Retry. |
503 | credential_refresh_busy | detail.error | Another request is renewing the same HubSpot credential. Any route that uses HubSpot can answer it. | Retry after Retry-After. Nothing is wrong with the credential. |
Inbound webhook sources
POST /api/webhooks/{connector_id}/{source_name}, the URL of a
webhook source:
| Status | Code | Read | Meaning | What to do |
|---|---|---|---|---|
401 | signature mismatch | detail | The signature header is missing or does not match the source’s secret. | Sign the body with the current secret. |
404 | event_source not found | detail | No source of that name on the connector. | Check the URL. |
410 | event_source disabled | detail | The source is disabled. | Enable it. |
400 | webhook_source_misconfigured | detail.error | The source’s config cannot handle the delivery. detail.message says why. | Fix the source definition and publish. |
400 | none | detail (string) | The source is not a webhook source, or the event type could not be read from the body. | Fix the URL or the payload. |
Connectors
| Status | Code | Read | Meaning | What to do |
|---|---|---|---|---|
422 | no_hubspot_credential, ambiguous_hubspot_credential | detail.error | Creating a connector with no HubSpot credential in the organization, or with several and no credential_id. detail.credentials lists them. | Connect HubSpot first, or pass credential_id. |
422 | credential_not_hubspot_oauth | detail.error | The credential_id is not a HubSpot connection. | Pass a HubSpot credential. |
402 | connector_limit_reached | detail.error | The plan’s connectors are used up. | Upgrade, or delete a connector. See Connectors. |
400 | Connector is <status>, cannot sync | detail | POST /api/connectors/{id}/sync on a connector that is paused or in error. | Resume the connector first. |
409 | rebind_confirmation_required | detail.error | Changing a connector’s HubSpot portal. detail describes the impact. | Resend the PATCH with "confirm_rebind": true in the body. See Changing the portal. |
409 | write_cap_release_required | detail.error | Changing the status of a connector held for review after its first sync. | An owner releases it with POST /api/connectors/{id}/write-cap/release. See First-sync write cap. |
409 | write_cap_resume_in_progress | detail.error | Changing the status while the held records are being sent on. Only error to paused is accepted. | Wait: the connector resumes by itself. To keep it stopped, pause it once it reads active. See First-sync write cap. |
409 | write_cap_not_tripped | detail.error | Releasing a connector that is not held: never paused by the cap, or already released. | Nothing to do. See First-sync write cap. |
402 | sla_monitoring_not_available | detail.error | SLA reporting on a plan that does not include it. | Contact sales. See SLA reporting. |
404 | export_not_found | detail.error | A scheduled export file that does not exist. | See scheduled exports. |
422 | invalid_export_path | detail.error | An export path that is not a file of this connector. | Use a path from the export listing. |
503 | exports_unavailable | detail.error | Exports cannot be read right now. | Retry later. |
Suspended or closing organization
Any route that would queue work for the organization refuses it while the organization’s syncs are suspended or while it is being closed: sending events and bulk imports, inbound webhooks, the legacy compat ingress, a manual sync and a full extract of a source, every replay (event, journal log, record mode, bulk import row) and attaching a HubSpot app install.
| Status | Code | Read | Meaning | What to do |
|---|---|---|---|---|
423 | org_suspended | detail.error | The organization’s syncs are suspended. detail.message says what to do. | Contact support@plugsync.com. |
423 | org_closing | detail.error | The organization is being closed. | An owner can cancel the closure from the organization settings. |
Event API ingest
Errors of POST /api/v1/events and of bulk import (/api/v1/events/bulk).
The full table with examples is in
the Event API reference.
| Status | Code | Read | Meaning | What to do |
|---|---|---|---|---|
401 | Missing x-api-key header, Invalid or revoked API key, Connector not found | detail | No valid connector key. | Send a live connector key in x-api-key. |
422 | none | detail (list) | The body fails validation. | Fix the fields named in loc. |
422 | payload_too_large: ... | detail (string) | A bulk import body over 10 MiB. The string gives the size and the limit. | Split the import into smaller requests. |
423 | Connector is <status>, ingestion is blocked | detail | Single events only (POST /api/v1/events): the connector is paused or in error. | Resume the connector. |
423 | org_suspended, org_closing | detail.error | See Suspended or closing organization. | |
409, 404, 502, 422 | body_mismatch, job_not_found, job_not_terminal: ..., row_not_found, row_not_replayable: ..., enqueue_failed | detail (string) | Bulk import only: an idempotency_key reused with a different body, an unknown job or row, a row replay on a job that has not finished or a row whose status cannot be replayed, a row replay without the fields its mode needs (422), or a job that could not be fully queued (502, some chunks may already be queued). | See Bulk import errors and Replay a failed row. On enqueue_failed, read the job status before sending again. |
429 | three causes | see below | See the three causes of 429. | |
503 | event_ingestion_unavailable, attachment_store_unavailable | detail.error | The event, or its attachment, could not be stored. Nothing was enqueued. | Retry with backoff. |
The three causes of 429
| Code | Read | Meaning | What to do |
|---|---|---|---|
Rate limit exceeded for org | detail (string) | More requests in the last second than the plan allows, across all the organization’s connectors and keys. Comes with Retry-After: 1 and the X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers. | Slow down and resend after a second. |
quota_exceeded | detail.error | The monthly event quota is used up. detail carries events_used_this_period, tier, upgrade_url and period_resets_at. | Upgrade, or wait for period_resets_at. See Events per month. |
connector_flow_breaker_open | detail.error | Single events only (POST /api/v1/events): every flow that would process this event type is paused after repeated failures. The event was rejected, not queued. detail.flows names each flow with its reason and retry_after_seconds. Comes with Retry-After. | Resend after Retry-After; fix the flow if it recurs. |
The per-plan limits and the full bodies are in the 429 section of the Event API reference. The monthly events of each plan are in Plan limits.
Reliability and replay
Replay, drain, identity mapping repair and the circuit breaker are described in Reliability.
| Status | Code | Read | Meaning | What to do |
|---|---|---|---|---|
409 | none | detail (string) | Replaying one event that cannot run: the event is quarantined without force=true, its status or direction is not replayable, its payload was never captured or was deleted under the retention policy, or no enabled flow of the active config handles its event type. The string names which. | See Triggering the replay. |
409 | This connector has no published config: there is no flow to replay the event through | detail | Replaying one event on a connector that was never published. | Publish, then replay. |
409 | The active config no longer validates (<flow> flow); republish the connector before replaying | detail | The published config fails today’s validation on the named flow. | Republish the connector, then replay. |
423 | Connector is <status>, replay is blocked | detail | Replaying the degraded events of the HubSpot journal log on a connector that is paused or in error. | Resume the connector first. |
409, 503 | none | detail (string) | Replaying from the HubSpot journal log without a usable HubSpot credential (409), or with HubSpot unreachable (503). | Reconnect HubSpot, or retry later. |
404, 409, 422, 502 | mapping_not_found, tombstone_not_found, mapping_changed, invalid_mapping_key, identity_store_unavailable | detail.error | Reading, removing or clearing one identity mapping. | See Repairing one identity mapping. |
409 | none | detail (string) | Starting a drain that is already running: a running drain cannot be extended. | See Discarding a backlog: drain. |
502 | Could not write the drain flag; the drain state is unchanged | detail | Starting or stopping a drain failed. | Retry: the drain is still in the state it was. |
404 | none | detail (string) | Retrying a flow whose breaker is not tripped. | Nothing to retry. |
Record mode replay
The record-mode replay routes under /api/connectors/{connector_id}/records,
described in
Record mode:
| Status | Code | Read | Meaning | What to do |
|---|---|---|---|---|
409 | Record mode is not enabled on this connector and its archive holds no records: ... | detail | Nothing to replay: record mode is off and nothing was archived. | Enable settings.record_mode, publish, and let events flow first. |
404 | Record key not found in this connector's archive | detail | The record key was never archived. | Check the key against the record listing. |
404 | Archived record no longer exists (expired by its retention policy) or is unreadable | detail | The archived payload is gone. | Re-send the record from its source. |
404 | Target connector not found | detail | The target connector is not in the organization. | Pick a connector of the same organization. |
423 | Target connector is <status>, replay is blocked | detail | The target connector is paused or in error. | Resume the target connector first. |
422 | 'to' must be after 'from', window cannot exceed 366 days ... | detail | The time window of a range replay or of the listing is empty or too long. | Fix from and to. |
404 | Replay job not found | detail | Unknown range replay job. | Check the job id. |
409 | Only queued/running jobs can be cancelled (this job is '<status>') | detail | Cancelling a range replay job that has already ended. | Nothing to cancel. |
Identity pre-warm
/api/connectors/{connector_id}/identity-prewarm (see
Running a pre-warm through the API),
also driven by
plugsync connector prewarm:
| Status | Code | Read | Meaning | What to do |
|---|---|---|---|---|
409 | no_active_config | detail.error | The connector has no published config. | Publish first. |
422 | no_eligible_entities, entity_not_eligible | detail.error | No entity, or not the requested ones (entities), can be pre-warmed. On entity_not_eligible, eligible lists those that can. | Pick from eligible; with no eligible entity, give a HubSpot schema an identity.property and publish. |
409 | prewarm_already_running | detail.error | A pre-warm is already running on the connector. | Wait for it, or cancel it. |
404 | job_not_found, connector_not_found | detail.error | Unknown job or connector. | Check the ids. |
409 | job_not_resumable, job_not_cancellable | detail.error | The job is in a state that does not allow it (job_not_cancellable names it in status). | Start a new pre-warm. |
HubSpot record read-back and identity tools
The read-back of a synced record and the identity tools under
/api/connectors/{connector_id}/identity/... answer with
{"detail": {"status": "<code>", "message": "..."}}: the code is in
detail.status.
| Status | Code | Meaning | What to do |
|---|---|---|---|
404 | mapping_not_found, entity_not_found | No identity mapping for that record, or no entity of that name. | Check the entity and the external id. |
404 | hubspot_object_not_found | The HubSpot record the mapping points at was deleted or archived (hubspot_id). | See Repairing one identity mapping. |
400 | association_target_invalid, search_filter_invalid | associations named something other than HubSpot object types, or the search filter is invalid. | Use HubSpot object types such as contacts and companies. |
409 | hubspot_not_connected | The connector has no usable HubSpot connection. | Reconnect HubSpot. |
409 | hubspot_object_type_invalid, no_active_config | The object type no longer exists on the portal, or there is no published config. | Fix the mapping and publish. |
422 | entity_no_hubspot_schema, entity_no_identity_property, adoption_object_type_not_supported, write_failed | The entity cannot be used for this tool, or HubSpot refused the write. | Read message. |
429 | hubspot_rate_limited | HubSpot rate limited the call. | Retry after a few seconds. |
502 | hubspot_auth_failed, hubspot_error, hubspot_unreachable | HubSpot refused the connection’s token, answered an unexpected error, or could not be reached. | Reconnect HubSpot on hubspot_auth_failed; retry otherwise. |
Plugins
How plugins are developed and invoked is in Plugins.
| Status | Code | Read | Meaning | What to do |
|---|---|---|---|---|
402 | plugin_system_not_allowed | detail.error | The plan does not include plugins. Creating a test-mode connector answers it too. | Contact sales. See Plugins and test connectors. |
409 | none | detail (string) | A setup or teardown lifecycle hook (/api/plugins/{id}/lifecycle/setup, /teardown) that cannot resolve the plugin: it is not promoted to live for a live connector, or the test connector has no creator. The string names which. | Promote the plugin, or run the hook on a connector created by a user. |
404 | No setup was ever recorded for this plugin/connector pair | detail | A teardown with no setup to undo. | Nothing to tear down. |
422 | plugin_capability_violation | detail.error | The pushed bundle calls a host its http capability does not allow, or a forbidden module (violations). | See Capability allow-list. |
400 | capability_missing | detail.error | A manual invoke with auth for a source the plugin has no auth: grant for. | Add the grant. See the dev loop. |
400 | ambiguous_source, source_without_outbound_auth, no_auth_headers, credential_error | detail.error | The source named for auth is ambiguous, has no outbound credentials, produced no headers, or its credential could not be read (reason). | Fix the source’s outbound auth. |
502 | function_error | detail.error | The handler threw. request_id finds it in the plugin logs. | Read the logs and fix the handler. |
502 | proxy_error | detail.error | The plugin could not be reached. | Retry; check the plugin’s status. |
Data export
Errors of /api/data-exports, detailed in Data export:
409 data_export_in_progress, 409 organization_closed,
429 data_export_limit_reached, 409 data_export_not_ready,
410 data_export_expired, 410 data_export_failed,
503 data_export_unavailable and 404 connector_not_found, all in
detail.error.
Billing
| Status | Code | Read | Meaning | What to do |
|---|---|---|---|---|
403 | user_auth_required | detail.error | Checkout, plan change preview, billing portal, billing details, order confirmations or agreement called with an organization key. GET /api/v1/billing/me accepts keys. | Use a signed-in session. |
403 | owner_required | detail.error | Billing details, order confirmations and the agreement are for owners. | Ask an owner. |
400 | already_on_tier, tier_not_purchasable, no_customer | detail.error | The organization is already on that plan, the plan cannot be bought self-service (tier), or the billing portal is opened before any purchase. | Pick another plan, or contact sales for the sales-led plans. |
409 | org_under_contract | detail.error | The organization is billed under a contract, not self-service. | Contact your account manager. |
409 | no_active_subscription | detail.error | The change needs an active subscription. | Subscribe first. |
409 | billing_currency_locked | detail.error | The checkout currency (requested_currency) differs from the one already used (existing_currency). | Check out in existing_currency. |
422 | sdi_or_pec_requires_italy | detail.error | An SDI code or PEC address for a country other than Italy. | Remove them, or set the country to Italy. |
404 | org_not_found, agreement_not_found, document_not_found | detail.error | No such organization, agreement or document. | Check the id. |
502 | billing_email_sync_failed | detail.error | The payment provider did not accept the new invoice email; nothing was saved. | Retry. |
503 | contract_documents_unavailable | detail.error | Contract documents cannot be read right now. | Retry later. |
Organization and HubSpot connection
| Status | Code | Read | Meaning | What to do |
|---|---|---|---|---|
404 | organization_not_found | detail.error | No such organization. | Check the org_id. |
401 | wrong_password, mfa_code_required, invalid_code | detail.error | Closing the organization without the right password or two-factor code. An account created with Google has no password until it sets one with the password reset. | Re-enter them. |
422 | confirmation_mismatch | detail.error | The confirmation name is not the organization’s name. | Type the exact name. |
403 | impersonation_not_allowed | detail.error | A plugsync support session opened on your account tried to close the organization, cancel a closure or attach a HubSpot install: those are left to you. | Do it from your own session. |
409 | org_already_closing, org_not_closing, org_erasure_started, org_has_commercial_agreement | detail.error | The closure is already requested, there is none to cancel, the deletion date has passed and the data is being deleted, or the organization has a commercial agreement. See Organization lifecycle. | For an agreement, contact support@plugsync.com to end it first. |
422 | legal_acceptance_required, legal_document_version_outdated | detail.error | Accepting the legal documents without covering all of them, or an old version (documents). | Accept the current version of each document listed. |
404 | template_not_found | detail.error | No connector template of that name. | Pick one from the template list. |
402 | portal_limit_reached | detail.error | Attaching a HubSpot app install to an organization that already uses all of its plan’s portals. The browser connect flow reports the same limit on the page it returns to. | Upgrade, or disconnect a portal. See HubSpot portals. |
404 | link_not_found | detail.error | Revoking a HubSpot connect link that does not exist. | Check the link id. |
409 | link_already_used | detail.error | Revoking a connect link that was already used. | Nothing to revoke. |
404, 400 | link_invalid | detail.error | Opening a connect link that is unknown (404) or malformed (400). | Ask an owner for a new link. See HubSpot connect links. |
410 | link_revoked, link_used, link_expired | detail.error | Opening a connect link that was revoked, already used, or expired (a link lasts 24 hours and connects one portal). | Ask an owner for a new link. |
422 | unknown_scope, invalid_return_to | detail.error | A HubSpot connect request with scopes plugsync does not know (scopes), or a return address outside the app. | Fix the request. |
404, 410 | install_not_found, install_expired | detail.error | A HubSpot app install that does not exist or took too long (an install waits 30 minutes). See installing from the HubSpot marketplace. | Install the app again from HubSpot. |
403 | install_other_browser, installer_mismatch | detail.error | The install is continued from another browser, or by a signed-in user whose email is not the one of the HubSpot user who installed it. | Continue in the same browser, as the installer; otherwise cancel the install and connect the portal from the dashboard. |
409 | portal_already_linked | detail.error | The portal is already connected to an organization. | Sign in to that organization. |
AI assistant
| Status | Code | Read | Meaning | What to do |
|---|---|---|---|---|
422 | credential_in_message | detail.code | A message to the assistant (POST /api/agent/chat) carries a token, an API key or a password (detected names the kinds). It was not stored nor sent to the model. | Remove the secret and save it as a credential instead. |
402 | agent_session_daily_limit_reached | detail.error | A trial organization starting a new assistant session over its daily sessions (limit, usage). Continuing an existing session is not counted. | Upgrade, or try again the next day (UTC). See AI assistant sessions. |
404 | Session not found, Connector not found | detail | Unknown session or connector. | Check the ids. |
409 | Session is already bound to a different connector | detail | A chat message names a connector other than the one the session works on. | Start a new session for that connector. |
400 | Cannot delete a finalized session | detail | Deleting a session that is already finalized. | Nothing to do. |
400 | Can only resume finalized sessions with a connector | detail | Resuming a session that is not finalized or has no connector. | Continue the session, or start a new one. |