Skip to main content
Every failure the API returns — from a typo in a filter to an internal fault — uses the same JSON envelope and an appropriate HTTP status code. There is exactly one shape to parse, so your error handling is one code path.

The envelope

Status codes

The HTTP status tells you the class of failure; the code tells you the specific one.

Handling failures

Branch on code, never on message. Codes are stable identifiers; messages are prose we may reword to be clearer. An integration that string-matches messages will break on a copy edit. A 404 does not always mean “never existed.” The API never confirms that another workspace’s resources exist, so a 404 on an id you believe you own can also mean the resource belongs to a different workspace. This is deliberate: it prevents anyone from probing ids to map out other tenants’ data. Retry 429 and 500; fix everything else. On 429, honor the Retry-After header before retrying — see Rate limits for the windows. On 500, GET requests are safe to retry with backoff; for writes, confirm whether the operation took effect before re-issuing it. Statuses in the 401–422 range describe a problem with the request itself — retrying the same request will fail the same way, so correct it first (for validation errors, param points at the field to fix).

Example: a 404 in full

Requesting rows from a list id that does not exist in your workspace:

Error code catalogue

Every code the API returns, grouped by area. doc_url in a live error response links to the matching section below.

UNAUTHORIZED

401 — The API token is missing, malformed, expired or revoked. Check that you are sending the key as the Basic-auth username with an empty password, and that the key has not been revoked in API Cockpit — see Authentication.

INSUFFICIENT_SCOPE

403 — This API token is not scoped for this endpoint. The key itself is valid; it was created without the scope this endpoint requires. Create a key with the right scopes, or use an unscoped key — see Scopes.

ENDPOINT_NOT_FOUND

404 — No endpoint matches this path and method. Check for typos in the path and confirm the HTTP method against the API reference; a POST to a GET-only path returns this code.

RATE_LIMITED

429 — You have exceeded the rate limit. Wait for the window to reset before retrying, honoring the Retry-After header — see Rate limits.

VALIDATION_FAILED

422 — The request failed validation against the endpoint’s schema: a missing required field, a value of the wrong type, or an unexpected field. param names the offending field and message says what was wrong with it; when more than one field fails, message lists them all. Fix the request before retrying — the same payload will keep failing.

INVALID_REQUEST

422 — The request passed schema validation but a value could not be used: a column value that cannot be coerced to the column’s type, or a campaign channel combination that is not supported. Correct the value and retry.

UNEXPECTED_ERROR

500 — An unexpected error occurred. Retry GET requests with backoff; for writes, verify state first. If it persists, contact support with the request_id.

INSUFFICIENT_CREDITS

402 or 422 — The workspace does not have enough credits for the operation. The request is rejected before any work is billed, so a failed request never consumes credits. Check your balance and see Credits.

LIST_NOT_FOUND

404 — No list with that id is visible to your workspace. Verify the id against GET /business/lists; an id belonging to another workspace also returns this code.

LIST_NAME_TAKEN

409 — A list with that name already exists in your workspace. Pick a different name, or add to the existing list instead of creating a new one.

LIST_NAME_AMBIGUOUS

409 — More than one list in your workspace has the name you passed in listName, so create-or-reuse cannot pick a destination — silently choosing one would pour contacts into the wrong list. Reference the destination by listId instead (GET /business/lists shows ids).

LIST_NAME_RESERVED

422 — The listName is a system list title (“All Saved Contacts”, “All Enriched Contacts”, and the other built-ins). System lists cannot be created or written to as a save destination; pick another name.

LIST_PROCESSING

409 — The source list is still being built or enriched, so a derived company list cannot be started from it yet. Poll GET /business/lists/{listId} until its completionStatus settles, then retry.

COLUMN_NAME_TAKEN

409 — The list already has a column with that name. Column names are unique per list; rename the new column or update the existing one — see Custom columns.

COLUMN_NAME_RESERVED

422 — The name is one of the reserved built-in column names (name, first name, last name, job title, company, email, phone …).

COLUMN_NOT_FOUND

404 — No column with that id exists on this list.

SEARCH_FILTERS_INVALID

422 — The search filters could not be interpreted. Check filter keys and values against GET /business/prospects/filter-options, and see Build a list from search for working examples.

SAVED_SEARCH_NOT_FOUND

404 — No saved search with that id is visible to your workspace. List available saved searches with GET /business/saved-searches.

SAVED_SEARCH_INVALID

422 — The saved search exists but its stored filters cannot be run as-is. Recreate or fix the search in the app, then run it again.

SAVED_SEARCH_NAME_AMBIGUOUS

409 — More than one saved search in your workspace has the name you passed in savedSearchName. Names are labels, not identifiers, so the API never silently picks one. Reference the search by id (GET /business/saved-searches lists ids), or rename one of the duplicates.

SAVED_SEARCH_FILTERS_UNSUPPORTED

422 — A filter field in the request cannot be stored in a saved search; param names it. Saved searches round-trip through the Fuse app’s filter rail, and this field has no stored representation there — run it as a direct search instead of saving it, or drop the field from the saved version.

SAVED_SEARCH_TYPE_MISMATCH

422 — The saved search stores COMPANY filters, which this endpoint cannot run; param is savedSearchId. Run it with POST /companies/search and savedSearchId instead.

QUERY_FILTERS_INVALID

422 — The natural-language query could not be converted into a runnable filter set — it was too vague to yield any concrete filter. Name concrete criteria (titles, locations, industries, company sizes), or pass structured filters directly. See Build a list from search.

EXCLUDE_COMPANY_LISTS_INVALID

422 — One or more ids in excludeCompanyLists do not resolve to company lists visible to your workspace. Check the ids and that each references a company list, not a contact list.

CONTACT_NOT_FOUND

404 — No contact with that id is visible to your workspace. Contacts belonging to another workspace also return this code.

CONTACT_LIST_REQUIRED

422 — The source list is a company list; companies are derived from a contact list’s rows.

CONTACT_NOT_IN_LIST

422 — One or more contactIds are not rows of this list. Send row ids from GET /business/lists/{listId}/rows.

EXPORT_NOT_FOUND

404 — No export job matching that id was found (it may have expired). Start a new export and poll the fresh job id — see Export a list.

EXPORT_LIMIT_EXCEEDED

422 — The campaign has more leads than a single export may contain.

CAMPAIGN_NOT_FOUND

404 — No campaign with that id is visible to your workspace. Campaigns belonging to another workspace also return this code.

CAMPAIGN_NAME_AMBIGUOUS

409 — More than one campaign has the name you passed in campaignName. Names are labels, not identifiers, so the API never silently picks one — reference the campaign by id.

CAMPAIGN_LIST_CAP_REACHED

422 — The campaign already carries its maximum number of attached lists (10), so the requested attach cannot happen. Detach a list in the app, or target a different campaign. Rejected before the save starts, so nothing is billed.

ALL_CONTACTS_ALREADY_ENRICHED

409 — Every contact in the destination list already carries the enrichment the request asked for, so there is nothing to run (and nothing is billed). Save with enrich: "none", request a different enrichment, or target a different list.

CAMPAIGN_NOT_APPROVABLE

409 — The campaign is not in a state that can be approved — it may already be approved or otherwise past the approval step. Fetch the campaign to check its current state — see Campaigns.

CAMPAIGN_NOT_READY

422 — The campaign is still being prepared and cannot be acted on yet. Poll the campaign until it is ready, then retry — see Campaigns.

CAMPAIGN_BUSY

409 — Another approve or stop is holding this campaign’s activation lock. Retry in a few seconds.

CAMPAIGN_INITIALIZING

409 — You sent listIds to PATCH /business/campaigns/{campaignId} while an AI-generated campaign’s background initialization was still running. The source lists are checked against the campaign’s sequence channels, and those are not settled until the steps have been generated. Poll GET /business/campaigns/{campaignId} until initializationStatus is completed (or failed), then retry. Other fields in the same request are unaffected — only listIds waits. Manual and template-based campaigns are initialized on creation and never return this code.

INVALID_CAMPAIGN_CHANNELS

422 — The channels value is not a valid channel combination for this campaign. Check the accepted values in the API reference.

INVALID_ROW_FILTERS

422 — The filters value is not a valid row-filter object.

LIST_INCOMPATIBLE_WITH_CHANNELS

422 — The list has no contacts reachable on the requested channels — it is empty, or no contact has an email address (or LinkedIn profile) for them. Enrich the list or choose channels its contacts can actually be reached on. Returned by POST /business/campaigns for the requested channels, and by PATCH /business/campaigns/{campaignId} when the new listIds cannot serve the campaign’s existing steps. When several lists are given they are judged together: one list with emails plus one with only LinkedIn profiles is fine for an email + LinkedIn sequence.

LIST_EMPTY

422 — The source list has no contacts to derive companies from. This can also appear transiently on a list populated moments ago: reachability stats are computed asynchronously, so a just-filled list may report as incompatible until they catch up. Retry after a minute or two before treating it as a real incompatibility.

SEQUENCE_STEP_NOT_FOUND

404 — No sequence step with that id exists on this campaign. List the campaign’s steps with GET /business/campaigns/{campaignId}/steps to get valid step ids.

CONNECTION_NOTE_TOO_LONG

422 — The body you sent for a linkedin_connection step is longer than the 200 characters LinkedIn allows in a connection-request note. On this step type body is the note itself, so shorten it to 200 characters or fewer (an empty body sends the request without a note). Other step types keep their usual body limit.

SCHEDULED_SEND_NOT_FOUND

404 — No queued send with that id is visible to your workspace. Send ids come from GET /business/campaigns/{campaignId}/scheduled-sends; an id belonging to another workspace also returns this code.

SCHEDULED_SEND_NOT_EDITABLE

409 — The send can no longer be edited: only a send still waiting to go out (scheduled or approval_required) accepts PATCH /business/scheduled-sends/{sendId}. A send that was already sent, skipped, stopped, overwritten by an earlier edit, or is waiting on a task is settled.

SCHEDULED_SEND_NOT_SKIPPABLE

409 — The send is already settled (sent, stopped, overwritten, replied or failed) and cannot be skipped.

TEMPLATE_NOT_FOUND

404 — The templateId does not resolve to a template visible to your workspace. Check the id, or omit it to let the campaign generate copy without a template.

WRITING_STYLE_NOT_FOUND

404 — The writingStyleId does not resolve to a writing style visible to your workspace. Check the id against the styles configured in the app.

KNOWLEDGE_HUB_NOT_FOUND

404 — The knowledgeHubId does not resolve to a knowledge hub visible to your workspace. List available hubs with GET /business/knowledge-hubs — see Knowledge hubs.

AGENT_NOT_FOUND

404 — The agentId does not resolve to an agent in your workspace. List agents with GET /business/agents.

AGENT_CONFIG_MISSING

409 — The draft carries no stored config to work from (a legacy draft saved before configs were persisted). Create the agent again.

AGENT_LIMIT_REACHED

403 — Free-plan accounts may hold at most 10 agents, drafts included. Delete an agent or upgrade the plan.

AGENT_NOT_A_DRAFT

409 — The agent is not a draft (status is not initializing): it was already started, or is paused, expired or failed. Only drafts are editable and activatable — duplicate the agent and work on the copy.

AGENT_NOT_RUNNING

409 — The agent has nothing to pause: it is still a draft (initializing), or its provider subscription is already gone. Drafts are refused deliberately, because a paused draft could never be started again (activate accepts drafts only).

AGENT_PROCESSING

409 — A run is in progress (status processing); the agent cannot be changed until it settles. Retry once it is active or paused.

AGENT_SIGNAL_REJECTED

422 — Web-monitor only: the search provider refused the prompt as a searchable signal. Rewrite the prompt rather than retrying it.

AGENT_SOURCE_LIST_EMPTY

422 — The source list holds nothing this agent kind can watch — no LinkedIn URLs, no companies, or no trackable contacts. Fill the list first.

AGENT_TYPE_UNSUPPORTED

409 — The agent is of a legacy kind this API can no longer edit or activate; its type reads as null.

RESEARCH_RUN_NOT_FOUND

404 — The runId does not resolve to a research run in your workspace.

KNOWLEDGE_HUB_DEFAULT_UNDELETABLE

409 — The default knowledge hub cannot be deleted. Make another hub the default with POST /business/knowledge-hubs/default, then delete this one.

KNOWLEDGE_HUB_NOT_READY

409 — The hub is still building (its status is processing) and cannot be deleted yet. Poll GET /business/knowledge-hubs/{hubId} until it finishes.

KNOWLEDGE_PAGE_NOT_FOUND

404 — The pageId does not resolve to a page on this hub. List pages with GET /business/knowledge-hubs/{hubId}/pages.

KNOWLEDGE_HUB_OWNER_ONLY

403 — The hub belongs to a teammate; you can read it, but only its owner can make it their default hub.

KNOWLEDGE_HUB_PAGES_UNAVAILABLE

409 — The hub predates knowledge pages and cannot be refreshed.

KNOWLEDGE_HUB_WEBSITE_NOT_FOUND

404url is not one of the hub’s websites.

KNOWLEDGE_PAGE_NOT_REGENERABLE

409 — The page has no cached sources to rebuild from (you authored it, or its sources were removed).

LEARNED_FACT_NOT_FOUND

404 — The factId does not resolve to a learned fact for your team.

LEARNED_FACT_NOT_ANONYMIZED

422 — The new claim names a person or customer, or carries a contract-level detail.

ATTACHMENT_NOT_FOUND

404 — The note has no attachment (or the note id is wrong). Note ids come from the hub detail response.

ATTACHMENT_ALREADY_EXISTS

409 — The note already holds a document; delete the note’s attachment first.

JOB_NOT_FOUND

404 — The jobId does not resolve to an async job for your workspace. Job ids come from 202 responses.

IMPORT_NOT_FOUND

404 — The importId does not resolve to an upload of yours. Import ids come from POST /business/imports and POST /business/imports/presign.

IMPORT_FILE_MISSING

400POST /business/imports needs either a multipart file part or an importId from a completed presigned upload.

IMPORT_FILE_UNSUPPORTED

422 — The file could not be parsed. Supported formats: CSV, XLS, XLSX.

IMPORT_FILE_TOO_LARGE

422 — The file is over the limit for this intake. Multipart accepts up to 10MB; use POST /business/imports/presign for files up to 50MB.

IMPORT_FILE_EMPTY

422 — The file parsed but has no data rows.

CITY_FILTER_UNRESOLVED

422 — NOT ONE of the filters.headquartersCity names geocoded to a city area, so the search was refused rather than run worldwide; names that do geocode are OR-ed together and a name that does not is dropped, so this fires only when every name fails. param is filters.headquartersCity.

CREDIT_LIMIT_EXCEEDS_PLAN

422 — The requested monthly credit limit is higher than the plan’s credit allowance.

CRM_NOT_CONNECTED

422 — This CRM is not connected for your workspace — connect it in the app’s integration settings.

FOLDER_NAME_TAKEN

409 — A folder with this name already exists for this list kind.

FOLDER_NOT_FOUND

404 — The requested folder was not found.

NOTE_NOT_FOUND

404 — No note with that id on this hub.

NO_LEADS_TO_EXPORT

422 — The campaign exists but has no enrolled leads to export yet.

NO_ROWS_TO_RESEARCH

422 — No row on the list matches filters, so there is nothing to research and nothing was charged.

PRIMARY_VALUE_NOT_ON_CONTACT

422 — The value must be one the contact already carries — primaries promote, never invent.

PROVENANCE_NOT_FOUND

404 — The column exists but no run has computed that row, so there is no provenance to show.

PROVIDERS_NOT_SUPPORTED

422 — ProviderIds was sent for a standard-engine column; only a deep_research column can be restricted to specific providers.

RUN_ALREADY_TERMINAL

409 — The run has already finished (completed, failed or cancelled) and cannot be cancelled.

STEP_ORDER_INVALID

422 — A linkedin_connection step would follow a linkedin_message step.

STEP_POSITION_TAKEN

409 — A step already occupies this sequenceNumber in the campaign.

STEP_PREVIEW_UNAVAILABLE

422 — There is nothing to render this step against: the campaign has no source list or no contact to sample, or generation produced no preview.

WEBSITE_TRACKING_NOT_SET_UP

404 — This account has no website-tracking record (no Webtraffic entry, or the caller resolves to no team owner) — set website tracking up in the app first.