Skip to main content
Every error from the Orbit Search API follows a consistent JSON shape with a machine-readable code field. Building your error handling around these codes — rather than HTTP status codes or message strings — gives you reliable, forward-compatible error detection. This page covers the full error format and every code grouped by category.

Error response format

All error responses use this shape:
{
  "status": "failed",
  "error": {
    "code": "ERROR_CODE",
    "message": "Human-readable description of the error."
  }
}
Some error codes include additional fields alongside code and message. For example, a credit-insufficient error also returns the amounts involved:
{
  "status": "failed",
  "error": {
    "code": "developer_api_credits_insufficient",
    "message": "Developer API credits are insufficient for this request",
    "requiredCredits": 2,
    "remainingCredits": 0
  }
}
Your error handling should always read the error.code field to determine what happened and how to respond.

Error codes by category

These errors indicate a problem with how the request is authenticated. Check your Authorization header and key configuration.
HTTPCodeDescription
401missing_api_keyNo Authorization: Bearer sk_orb_... header was provided. Add the header with a valid developer API key.
403invalid_api_keyThe key is malformed, revoked, expired, or unknown. Verify the key is active in your key list and has not been revoked or expired.
403missing_api_key_scopeThe key does not include the scope required for this endpoint. For search, profile query, and Deep Search, the key needs search:read; for profile reads, it needs profile:read. Issue a replacement key with the correct scopes in the dashboard.
403api_key_management_requires_user_authA developer API key attempted to create, list, revoke, or delete keys. Manage keys in the Orbit developer dashboard instead.
Example handling:
if (error.code === "invalid_api_key") {
  // Key was revoked or expired — trigger key rotation flow
  await rotateApiKey();
} else if (error.code === "missing_api_key_scope") {
  // Log a configuration error — this needs a human to fix
  logger.error("API key missing required scope", { code: error.code });
}
These errors are returned with HTTP 400 when the search request body fails validation. Fix the request body before retrying — retrying with the same body will produce the same error.
CodeDescription
developer_query_requiredThe query field is missing or empty. Provide a non-empty string.
developer_num_users_requiredThe numUsers field is missing or not a positive integer. Provide a valid positive integer.
developer_num_users_limit_exceedednumUsers exceeds the maximum of 100. Reduce the value to 100 or below.
developer_user_id_override_forbiddenThe request body includes a userId field, which is not permitted for developer API key requests. Remove the field.
developer_search_replay_unsupportedThe request body includes a searchId field. Search replay is not supported for developer API key requests. Remove the field.
developer_profile_query_requiredProfile Query is missing a non-empty query.
developer_profile_query_too_longProfile Query received a query longer than 1,000 characters.
developer_profile_query_limit_invalidProfile Query received a limit that is not a positive integer.
developer_profile_query_limit_exceededProfile Query received a limit greater than 50.
developer_deep_search_field_unsupportedDeep Search received a top-level body field other than requestId, runShape, profileId, email, phoneNumber, linkedinUrl, urls, usernames, or structuredIntent. Legacy fields (mode, partialProfile, dry_run, options, profile_id, orbit_id) are flagged with a replacement hint.
developer_deep_search_input_requiredDeep Search did not receive an identity signal (profileId, structuredIntent, email, phoneNumber, linkedinUrl, urls, or usernames).
developer_deep_search_email_invalidDeep Search received a malformed email.
developer_deep_search_phone_invalidDeep Search received a malformed phoneNumber.
developer_deep_search_linkedin_invalidDeep Search received a malformed linkedinUrl or a non-profile LinkedIn URL.
developer_deep_search_field_invalidDeep Search received a urls or usernames value that is not an array of strings.
developer_deep_search_url_invalidDeep Search received a urls entry that is not a valid http(s) URL.
developer_deep_search_run_shape_invalidDeep Search received a runShape other than partial_only, partial_plus_full, full_generation_only, or candidate_discovery.
developer_deep_search_request_id_invalidDeep Search received a requestId that is not a non-empty string.
developer_deep_search_profile_id_invalidDeep Search received a profileId that is not a non-empty string.
developer_deep_search_personalization_unsupportedDeep Search received structuredIntent.personalization, which requires synchronous search user context.
developer_deep_search_unprocessable_seedThe provided Deep Search identity signals could not start a run.
structured_intent_requiredstructuredIntent was provided but its value is not a valid object.
structured_intent_invalidstructuredIntent is malformed or contains unsupported values.
structured_intent_version_unsupportedstructuredIntent.version must be "v1".
structured_intent_entity_clauses_unsupportedentityClauses are not part of the public structured DSL.
structured_intent_server_owned_fieldThe request includes a server-owned structured intent field.
Example handling:
const VALIDATION_ERRORS = new Set([
  "developer_query_required",
  "developer_num_users_required",
  "developer_num_users_limit_exceeded",
  "developer_user_id_override_forbidden",
  "developer_search_replay_unsupported",
  "developer_profile_query_required",
  "developer_profile_query_too_long",
  "developer_profile_query_limit_invalid",
  "developer_profile_query_limit_exceeded",
  "developer_deep_search_field_unsupported",
  "developer_deep_search_input_required",
  "developer_deep_search_email_invalid",
  "developer_deep_search_phone_invalid",
  "developer_deep_search_linkedin_invalid",
  "developer_deep_search_field_invalid",
  "developer_deep_search_url_invalid",
  "developer_deep_search_run_shape_invalid",
  "developer_deep_search_request_id_invalid",
  "developer_deep_search_personalization_unsupported",
  "developer_deep_search_unprocessable_seed",
  "structured_intent_required",
  "structured_intent_invalid",
  "structured_intent_version_unsupported",
  "structured_intent_entity_clauses_unsupported",
  "structured_intent_server_owned_field",
]);

if (VALIDATION_ERRORS.has(error.code)) {
  // Do not retry — fix the request body
  throw new Error(`Invalid search request: ${error.code}`);
}
These errors relate to organization API key requirements, directory access, and directory search scoping.
HTTPCodeDescription
403developer_api_key_organization_requiredThe requested operation requires an organization API key. Personal API keys are rejected for directory scopes. Switch to an organization API key.
403developer_api_key_organization_forbiddenThe organization API key is not authorized for the requested organization search scope. Ensure the key belongs to the correct organization.
404search_directory_not_foundOne or more requested directories do not exist, have been archived, or are unavailable for search. Verify the directoryId values and check that the directories are active.
400search_directory_cross_org_scope_unsupportedA multi-directory search ("type": "directories") included directories from more than one organization. All directories in a single request must belong to the same organization.
403search_directory_access_api_key_forbiddenThe organization API key does not have a matching directory grant with search or manage permission. Add a grant for this key or use a key that already has access.
Directory access validation runs before credits are charged. If your key lacks a directory grant, no credits are consumed on the rejected request.
Example handling:
if (error.code === "search_directory_not_found") {
  // Directory was archived or deleted — check directory list
  const directories = await listDirectories(organizationId);
  logger.warn("Directory not found", { directoryId, directories });
} else if (error.code === "search_directory_access_api_key_forbidden") {
  // Key lacks a grant — needs an admin to add one
  logger.error("API key lacks directory grant", { code: error.code });
}
These errors indicate you have hit a spending or throughput limit. They are separate from one another — a request can fail with 429 even when credits remain, and a request can fail with 402 even when the rate limit has capacity.
HTTPCodeDescription
402developer_api_credits_insufficientYour remaining credits are lower than the cost of the requested operation (2 credits for Search, 1 for Profile Query or profile reads, 10 for Deep Search by default). The response includes requiredCredits and remainingCredits. Top up your credit balance before retrying.
429developer_api_key_rate_limitedThe per-key rate limit has been exceeded. Search and Profile Query default to 25 requests per second with bursts up to 100 requests. Profile reads default to 50 requests per second with bursts up to 250 requests. Deep Search start requests default to 5 requests per second with bursts up to 25 requests; Deep Search status polling has its own bucket at 25 requests per second with bursts up to 150 requests. Back off and retry after the bucket refills.
Credit-insufficient response example:
{
  "status": "failed",
  "error": {
    "code": "developer_api_credits_insufficient",
    "message": "Developer API credits are insufficient for this request",
    "requiredCredits": 2,
    "remainingCredits": 0
  }
}
Example handling:
if (error.code === "developer_api_key_rate_limited") {
  // Exponential backoff
  await sleep(backoffMs);
  return retry(request);
}

if (error.code === "developer_api_credits_insufficient") {
  const { requiredCredits, remainingCredits } = error;
  logger.warn("Insufficient credits", { requiredCredits, remainingCredits });
  // Notify operators or pause non-essential requests
}
Check the X-Developer-API-Credits-Remaining response header after each successful request to track your balance proactively. This lets you alert before you hit zero rather than discovering the problem at request time.
These errors are returned with HTTP 409 when there is a conflict with a previously submitted Idempotency-Key header value.
CodeDescription
developer_api_idempotency_key_conflictYou reused an idempotency key with different request parameters. Each unique idempotency key is permanently bound to the parameters of the first request that used it. Generate a new key for this request.
developer_api_idempotency_key_refundedThe idempotency key belongs to a request that was refunded (for example, an empty-result search). You cannot reuse a refunded key for a new charge. Generate a new idempotency key and retry.
Example handling:
if (error.code === "developer_api_idempotency_key_conflict") {
  // Bug in your code — you're reusing a key with different params
  throw new Error("Idempotency key reused with different parameters");
}

if (error.code === "developer_api_idempotency_key_refunded") {
  // Safe to retry — just generate a fresh key
  return retry({ ...request, idempotencyKey: crypto.randomUUID() });
}
These errors are specific to POST /v2/developer/deep-search and GET /v2/developer/deep-search/:requestId.
HTTPCodeDescription
400developer_deep_search_field_unsupportedThe body includes a top-level field other than requestId, runShape, profileId, email, phoneNumber, linkedinUrl, urls, usernames, or structuredIntent. Legacy fields (mode, partialProfile, dry_run, options, profile_id, orbit_id) are flagged with a replacement hint.
400developer_deep_search_input_requiredThe body is missing an identity signal (profileId, structuredIntent, email, phoneNumber, linkedinUrl, urls, or usernames).
400developer_deep_search_email_invalidemail is malformed.
400developer_deep_search_phone_invalidphoneNumber is malformed.
400developer_deep_search_linkedin_invalidlinkedinUrl is malformed or is not a LinkedIn profile URL.
400developer_deep_search_field_invalidurls or usernames is not an array of strings.
400developer_deep_search_url_invalidurls contains a value that is not a valid http(s) URL.
400developer_deep_search_run_shape_invalidrunShape is not one of partial_only, partial_plus_full, full_generation_only, candidate_discovery.
400developer_deep_search_request_id_invalidrequestId is not a non-empty string.
400developer_deep_search_profile_id_invalidprofileId is not a non-empty string.
400developer_deep_search_personalization_unsupportedThe structured intent includes personalization, which requires synchronous search user context.
400developer_deep_search_unprocessable_seedThe provided identity signals could not start a Deep Search run.
400developer_deep_search_invalid_requestThe request body was rejected; the message describes what to fix.
400structured_intent_requiredstructuredIntent was provided but its value is not a valid object.
404developer_deep_search_run_not_foundThe requestId does not match a known Deep Search run.
502developer_deep_search_request_failedDeep Search did not accept the request or could not be reached. Retry later.
503developer_deep_search_unavailable_for_requestDeep Search is not available for this request.
503developer_deep_search_unavailableDeep Search is currently unavailable. Retry later.
503developer_deep_search_not_configuredDeep Search is not configured in this environment.
Deep Search idempotency is handled by the requestId body field, not the Idempotency-Key header. Re-sending the same requestId returns 200 with status: "already_running" instead of a conflict error.
HTTPCodeDescription
404developer_profile_not_foundThe profile ID does not resolve to a public Orbit profile. The profile may have been removed, made private, or the ID may be incorrect. Profile reads and Profile Query requests that return this error are automatically refunded.
Example handling:
if (error.code === "developer_profile_not_found") {
  // No credits were consumed — safe to skip or log
  logger.info("Profile not found, skipping", { profileId });
}

HTTP status code summary

StatusCodes
400developer_query_required, developer_num_users_required, developer_num_users_limit_exceeded, developer_user_id_override_forbidden, developer_search_replay_unsupported, developer_profile_query_required, developer_profile_query_too_long, developer_profile_query_limit_invalid, developer_profile_query_limit_exceeded, structured_intent_required, structured_intent_invalid, structured_intent_version_unsupported, structured_intent_entity_clauses_unsupported, structured_intent_server_owned_field, search_directory_cross_org_scope_unsupported, developer_deep_search_field_unsupported, developer_deep_search_field_invalid, developer_deep_search_url_invalid, developer_deep_search_input_required, developer_deep_search_email_invalid, developer_deep_search_phone_invalid, developer_deep_search_linkedin_invalid, developer_deep_search_run_shape_invalid, developer_deep_search_request_id_invalid, developer_deep_search_personalization_unsupported, developer_deep_search_unprocessable_seed, developer_deep_search_invalid_request
401missing_api_key
402developer_api_credits_insufficient
403invalid_api_key, missing_api_key_scope, api_key_management_requires_user_auth, developer_api_key_organization_required, developer_api_key_organization_forbidden, search_directory_access_api_key_forbidden
404developer_profile_not_found, search_directory_not_found, developer_deep_search_run_not_found
409developer_api_idempotency_key_conflict, developer_api_idempotency_key_refunded
429developer_api_key_rate_limited
502developer_deep_search_request_failed
503developer_deep_search_unavailable_for_request, developer_deep_search_unavailable, developer_deep_search_not_configured